Compare commits

..

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

898 changed files with 9889 additions and 15272 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,55 @@
#
# 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.56.0 \
--hash=sha256:003548eadd674175510773f73fb2060bb46adb77c94854af3e0cc5bc70260049 \
--hash=sha256:0073b62c3438cf0058488c002ea90489e8801d3a7af5ce5f7c05c105bee815c3 \
--hash=sha256:1088182f68c303b50ca4dc0c82d42083d176cba37af1937e1a976a31149d4d14 \
--hash=sha256:133bedb9a5c6376ad43e6518b7e2cd2f866a05b1998f14842631d5feb36b5786 \
--hash=sha256:14a3e3e6b211660db54ca1ef7006401e4a694e53ffd4553ab9bc87ead01d0f05 \
--hash=sha256:17f39313b649037f6c800209984a11fc256a6137cbe5487091c6c7187cae4685 \
--hash=sha256:193b86e9f769320bc98ffdb42accafb5d0c8c49bd62884f1c0702bc598b3f0a2 \
--hash=sha256:2d351275f73ebdd81dd5b09a8b8dac7a30f29a279d41e1c1192aedf1b6dced40 \
--hash=sha256:300c310bb725b2bdb4f5fc7e148e190bd69f01925c7ab437b9c0ca3e1c7cd9ba \
--hash=sha256:331954d002dbf5e704c7f3756028e21db07097c19722569983ba4d74df014000 \
--hash=sha256:38b947de71748bab150259ee05a775e8a0635891568e9fdb3cdd7d0e0004e62f \
--hash=sha256:3cf4f8d2a30b454ac682e12c61831dcb174950c406011418e739de592bbf8f76 \
--hash=sha256:3fd3fccb7b9adaaecfa79ad51b759f2123e1aba97f857936ce044d4f029abd71 \
--hash=sha256:442ad4122468d0e47d83bc59d0e91b474593a8c813839e1872e47c7a0cb53b10 \
--hash=sha256:47b5e4680002ae1756d3ae3b6114e20aaee6cc5c69d1e5911f5ffffd3ee46c6b \
--hash=sha256:53f5e9767978a4daf46f28e09dbeb7d010319924ae622f7b56174b777258e5ba \
--hash=sha256:62b4c6802fa28e14dba010e75190e0e6228513573f1eeae57b11aa1a39b7e5b1 \
--hash=sha256:62cc1253827d1e500fde9dbe981219fea4eb000fd63402283472d38e7d8aa1c6 \
--hash=sha256:654ac4583e2d7c62aebc6fc6a4c6736f078f50300e18aa105d87ce8925cfac31 \
--hash=sha256:661a8995d11e6e4914a44ca7d52d1286e2d9b154f685a4d1f69add8418961563 \
--hash=sha256:6c1d38642ca2dddc7ae992ef5d026e5061a84f10ff2b906be5680ab089f55bb8 \
--hash=sha256:6e81c1cc80c1d8bf071356cc3e0e25071fbba1c75afc48d41b26048980b3c771 \
--hash=sha256:705837eae384fe21cee5e5746fd4f4b2f06f87544fa60f60740007e0aa600311 \
--hash=sha256:7ef04bc7827adb7532be3d14462390dd71287644516af3f1e67f1e6ff9c6d6df \
--hash=sha256:86b2a1013ef7a64d2e94606632683f07712045ed86d937c11ef4dde97319c086 \
--hash=sha256:8d1613abd5af2f93c05867b3a3759a56e8bf97eb79b1da76b2bc10892f96ff16 \
--hash=sha256:965d0209e6dbdb9416100123b6709cb13f5232e2d52d17ed37f9df0cc31e2b35 \
--hash=sha256:96a4271f63a615bcb902b9f56de00ea225d6896052c49f20d0c91e9f43529a29 \
--hash=sha256:9d94449ad0a5f2a8bf5d2f8d71d65088aee48adbe45f3c5f8e00e3ad861ed81a \
--hash=sha256:9da650cb29bc098b8cfd15ef09009c914b35c7986c8fa9f08b51108b7bc393b4 \
--hash=sha256:a05d1f07eb0a7d755fbe01fee1fd255c3a4d3730130cf1bfefb682d18fd2fcea \
--hash=sha256:a114d1567e1a1586b7e9e7fc2ff686ca542a82769a296cef131e4c4af51e58f4 \
--hash=sha256:a1af375734018951c31c0737d04a9d5fd0a353a0253db5fbed2ccd44eac62d8c \
--hash=sha256:b23d30a2c0b992fb1c4f8ac9bfde44b5586d23457759b6cf9a787f1a35179ee0 \
--hash=sha256:bc871904a53a9d4d908673c6faa15689874af1c7c5ac403a8e12d967ebd0c0dc \
--hash=sha256:bce60f9a977c9d3d51de475af3f3581d9b36952e1f8fc19a1f2254f1dda7ce9c \
--hash=sha256:bd9825822e7bb243f285013e653f6741954d8147427aaa0324a862cdbf4cbf62 \
--hash=sha256:ca7962e8e5fc047cc4e59389959843aafbf7445b6c08c20d883e60ced46370a5 \
--hash=sha256:d0cb73ccf7f6d7ca8d0bc7ea8ac0a5b84969a41c56ac3ac3422a24df2680546f \
--hash=sha256:d54a45d30251f1d729e69e5b675f9a08b7da413391a1227781e2a297fa37f6d2 \
--hash=sha256:d6ca96d1b61a707ba01a43318c9c40aaf11a5a568d1e61146fafa6ab20890793 \
--hash=sha256:d6f195c14c01bd057bc9b4f70756b510e009c83c5ea67b25ced3e2c38e6ee6e9 \
--hash=sha256:e2cad98c94833465bcf28f51c248aaf07ca022efc6a3eba750ad9c1e0256d278 \
--hash=sha256:e2e993e8db36306cc3f1734edc8ea67906c55f98683d6fd34c3fc5593fdbba4c \
--hash=sha256:e9270505a19361e81eecdbc2c251ad1e1a9a9c2ad75fa022ccdee533f55535dc \
--hash=sha256:f20e2c0dfab82983a90f3d00703ac0960412036153e5023eed2b4641d7d5e692 \
--hash=sha256:f36a0868f47b7566237640c026c65a86d09a3d9ca5df1cd039e30a1da73098a0 \
--hash=sha256:f59746f7953f69cc3290ce2f971ab01056e55ddd0fb8b792c31a8acd7fee2d28 \
--hash=sha256:fa760e5fe8b50cbc2d71884a1eff2ed2b95a005f02dda2fa431560db0ddd927f \
--hash=sha256:ffda9b8cd9cb8b301cae2602ec62375b59e2e2108a117746f12215145e3f786c
# via -r requirements-fonttools.in

View file

@ -4,84 +4,146 @@
#
# 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.56.0 \
--hash=sha256:003548eadd674175510773f73fb2060bb46adb77c94854af3e0cc5bc70260049 \
--hash=sha256:0073b62c3438cf0058488c002ea90489e8801d3a7af5ce5f7c05c105bee815c3 \
--hash=sha256:1088182f68c303b50ca4dc0c82d42083d176cba37af1937e1a976a31149d4d14 \
--hash=sha256:133bedb9a5c6376ad43e6518b7e2cd2f866a05b1998f14842631d5feb36b5786 \
--hash=sha256:14a3e3e6b211660db54ca1ef7006401e4a694e53ffd4553ab9bc87ead01d0f05 \
--hash=sha256:17f39313b649037f6c800209984a11fc256a6137cbe5487091c6c7187cae4685 \
--hash=sha256:193b86e9f769320bc98ffdb42accafb5d0c8c49bd62884f1c0702bc598b3f0a2 \
--hash=sha256:2d351275f73ebdd81dd5b09a8b8dac7a30f29a279d41e1c1192aedf1b6dced40 \
--hash=sha256:300c310bb725b2bdb4f5fc7e148e190bd69f01925c7ab437b9c0ca3e1c7cd9ba \
--hash=sha256:331954d002dbf5e704c7f3756028e21db07097c19722569983ba4d74df014000 \
--hash=sha256:38b947de71748bab150259ee05a775e8a0635891568e9fdb3cdd7d0e0004e62f \
--hash=sha256:3cf4f8d2a30b454ac682e12c61831dcb174950c406011418e739de592bbf8f76 \
--hash=sha256:3fd3fccb7b9adaaecfa79ad51b759f2123e1aba97f857936ce044d4f029abd71 \
--hash=sha256:442ad4122468d0e47d83bc59d0e91b474593a8c813839e1872e47c7a0cb53b10 \
--hash=sha256:47b5e4680002ae1756d3ae3b6114e20aaee6cc5c69d1e5911f5ffffd3ee46c6b \
--hash=sha256:53f5e9767978a4daf46f28e09dbeb7d010319924ae622f7b56174b777258e5ba \
--hash=sha256:62b4c6802fa28e14dba010e75190e0e6228513573f1eeae57b11aa1a39b7e5b1 \
--hash=sha256:62cc1253827d1e500fde9dbe981219fea4eb000fd63402283472d38e7d8aa1c6 \
--hash=sha256:654ac4583e2d7c62aebc6fc6a4c6736f078f50300e18aa105d87ce8925cfac31 \
--hash=sha256:661a8995d11e6e4914a44ca7d52d1286e2d9b154f685a4d1f69add8418961563 \
--hash=sha256:6c1d38642ca2dddc7ae992ef5d026e5061a84f10ff2b906be5680ab089f55bb8 \
--hash=sha256:6e81c1cc80c1d8bf071356cc3e0e25071fbba1c75afc48d41b26048980b3c771 \
--hash=sha256:705837eae384fe21cee5e5746fd4f4b2f06f87544fa60f60740007e0aa600311 \
--hash=sha256:7ef04bc7827adb7532be3d14462390dd71287644516af3f1e67f1e6ff9c6d6df \
--hash=sha256:86b2a1013ef7a64d2e94606632683f07712045ed86d937c11ef4dde97319c086 \
--hash=sha256:8d1613abd5af2f93c05867b3a3759a56e8bf97eb79b1da76b2bc10892f96ff16 \
--hash=sha256:965d0209e6dbdb9416100123b6709cb13f5232e2d52d17ed37f9df0cc31e2b35 \
--hash=sha256:96a4271f63a615bcb902b9f56de00ea225d6896052c49f20d0c91e9f43529a29 \
--hash=sha256:9d94449ad0a5f2a8bf5d2f8d71d65088aee48adbe45f3c5f8e00e3ad861ed81a \
--hash=sha256:9da650cb29bc098b8cfd15ef09009c914b35c7986c8fa9f08b51108b7bc393b4 \
--hash=sha256:a05d1f07eb0a7d755fbe01fee1fd255c3a4d3730130cf1bfefb682d18fd2fcea \
--hash=sha256:a114d1567e1a1586b7e9e7fc2ff686ca542a82769a296cef131e4c4af51e58f4 \
--hash=sha256:a1af375734018951c31c0737d04a9d5fd0a353a0253db5fbed2ccd44eac62d8c \
--hash=sha256:b23d30a2c0b992fb1c4f8ac9bfde44b5586d23457759b6cf9a787f1a35179ee0 \
--hash=sha256:bc871904a53a9d4d908673c6faa15689874af1c7c5ac403a8e12d967ebd0c0dc \
--hash=sha256:bce60f9a977c9d3d51de475af3f3581d9b36952e1f8fc19a1f2254f1dda7ce9c \
--hash=sha256:bd9825822e7bb243f285013e653f6741954d8147427aaa0324a862cdbf4cbf62 \
--hash=sha256:ca7962e8e5fc047cc4e59389959843aafbf7445b6c08c20d883e60ced46370a5 \
--hash=sha256:d0cb73ccf7f6d7ca8d0bc7ea8ac0a5b84969a41c56ac3ac3422a24df2680546f \
--hash=sha256:d54a45d30251f1d729e69e5b675f9a08b7da413391a1227781e2a297fa37f6d2 \
--hash=sha256:d6ca96d1b61a707ba01a43318c9c40aaf11a5a568d1e61146fafa6ab20890793 \
--hash=sha256:d6f195c14c01bd057bc9b4f70756b510e009c83c5ea67b25ced3e2c38e6ee6e9 \
--hash=sha256:e2cad98c94833465bcf28f51c248aaf07ca022efc6a3eba750ad9c1e0256d278 \
--hash=sha256:e2e993e8db36306cc3f1734edc8ea67906c55f98683d6fd34c3fc5593fdbba4c \
--hash=sha256:e9270505a19361e81eecdbc2c251ad1e1a9a9c2ad75fa022ccdee533f55535dc \
--hash=sha256:f20e2c0dfab82983a90f3d00703ac0960412036153e5023eed2b4641d7d5e692 \
--hash=sha256:f36a0868f47b7566237640c026c65a86d09a3d9ca5df1cd039e30a1da73098a0 \
--hash=sha256:f59746f7953f69cc3290ce2f971ab01056e55ddd0fb8b792c31a8acd7fee2d28 \
--hash=sha256:fa760e5fe8b50cbc2d71884a1eff2ed2b95a005f02dda2fa431560db0ddd927f \
--hash=sha256:ffda9b8cd9cb8b301cae2602ec62375b59e2e2108a117746f12215145e3f786c
# via -r requirements-fonttools.in
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.7.0 \
--hash=sha256:08efbe84803eed07f863b05092d653a9d348f7038761d900412fddf56deb0284 \
--hash=sha256:ae3f12953045f3c7c60e27f2af1ad862f14dee125b4ed9bcb8a842a5080dbf85
# 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
ninja==1.11.1.3 \
--hash=sha256:04d48d14ea7ba11951c156599ab526bdda575450797ff57c6fdf99b2554d09c7 \
--hash=sha256:114ed5c61c8474df6a69ab89097a20749b769e2c219a452cb2fadc49b0d581b0 \
--hash=sha256:17978ad611d8ead578d83637f5ae80c2261b033db0b493a7ce94f88623f29e1b \
--hash=sha256:1ad2112c2b0159ed7c4ae3731595191b1546ba62316fc40808edecd0306fefa3 \
--hash=sha256:2883ea46b3c5079074f56820f9989c6261fcc6fd873d914ee49010ecf283c3b2 \
--hash=sha256:28aea3c1c280cba95b8608d50797169f3a34280e3e9a6379b6e340f0c9eaeeb0 \
--hash=sha256:2b4879ea3f1169f3d855182c57dcc84d1b5048628c8b7be0d702b81882a37237 \
--hash=sha256:53409151da081f3c198bb0bfc220a7f4e821e022c5b7d29719adda892ddb31bb \
--hash=sha256:56ada5d33b8741d298836644042faddebc83ee669782d661e21563034beb5aba \
--hash=sha256:7fa2247fce98f683bc712562d82b22b8a0a5c000738a13147ca2d1b68c122298 \
--hash=sha256:8c4bdb9fd2d0c06501ae15abfd23407660e95659e384acd36e013b6dd7d8a8e4 \
--hash=sha256:a27e78ca71316c8654965ee94b286a98c83877bfebe2607db96897bbfe458af0 \
--hash=sha256:a38c6c6c8032bed68b70c3b065d944c35e9f903342875d3a3218c1607987077c \
--hash=sha256:a4a3b71490557e18c010cbb26bd1ea9a0c32ee67e8f105e9731515b6e0af792e \
--hash=sha256:b6966f83064a88a51693073eea3decd47e08c3965241e09578ef7aa3a7738329 \
--hash=sha256:bc3ebc8b2e47716149f3541742b5cd8e0b08f51013b825c05baca3e34854370d \
--hash=sha256:edfa0d2e9d7ead1635b03e40a32ad56cc8f56798b6e2e9848d8300b174897076
# via -r requirements.in
# 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
@ -58,6 +58,20 @@ jobs:
- 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))
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:
- image: ubuntu
@ -66,11 +80,9 @@ 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
@ -83,10 +95,9 @@ 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 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
@ -99,10 +110,9 @@ 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 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
@ -121,21 +131,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
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 +149,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 +157,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
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 +175,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 +199,7 @@ workflows:
branches:
ignore: /.*/
- fedora-valgrind
- alpine
- asan-ubsan
- tsan
- msan

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@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts

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

@ -34,10 +34,9 @@ jobs:
libglib2.0-dev \
libgraphite2-dev \
libicu-dev \
pkg-config \
help2man
pkg-config
- name: Setup Python
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
with:
python-version: '3.12'
- name: Install Python Dependencies

View file

@ -36,7 +36,7 @@ jobs:
ninja \
pkgconf
- name: Setup Python
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
with:
python-version: '3.12'
- name: Install Python Dependencies

View file

@ -35,7 +35,7 @@ jobs:
variant: sccache
key: ${{ github.job }}-${{ matrix.os }}-${{ matrix.ARCH }}
- name: Setup Python
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
with:
python-version: '3.12'
- name: Setup MSVC

View file

@ -21,10 +21,13 @@ 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}
@ -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@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
with:
name: libharfbuzz-${{ matrix.MSYS2_ARCH }}
path: ./build/src/libharfbuzz-*.dll

View file

@ -34,7 +34,7 @@ jobs:
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@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.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@fc7e4a0fa01c3cca5fd6a1fddec5c0740c977aa2 # v3.28.14
uses: github/codeql-action/upload-sarif@9e8d0789d4a0fa9ceb6b1738f7e269594bdd67f0 # v3.28.9
with:
sarif_file: results.sarif

View file

@ -233,7 +233,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)

117
NEWS
View file

@ -1,118 +1,7 @@
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
@ -337,10 +226,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,8 @@
[![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)
[![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 +34,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 +50,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 +84,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 +95,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,8 +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>

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>
@ -354,7 +341,6 @@ 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
@ -364,12 +350,9 @@ hb_coretext_font_set_funcs
<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_face_get_font_face
hb_directwrite_font_create
hb_directwrite_font_get_dw_font_face
hb_directwrite_font_set_funcs
hb_directwrite_font_get_dw_font
</SECTION>
<SECTION>
@ -378,10 +361,7 @@ 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 +455,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 +514,16 @@ 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 +549,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>
@ -955,10 +927,6 @@ hb_subset_serialize_object_t
hb_subset_serialize_or_fail
<SUBSECTION Private>
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

@ -1,12 +1,11 @@
project('harfbuzz', ['c', 'cpp'],
meson_version: '>= 0.60.0',
version: '11.0.1',
project('harfbuzz', 'c', 'cpp',
meson_version: '>= 0.55.0',
version: '10.3.0',
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,7 +315,7 @@ 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
@ -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,10 +464,12 @@ 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())
if meson.version().version_compare('>=0.57.0')
# 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())
endif
build_summary = {
'Directories':

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

@ -21,6 +21,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, CORETEXT };
enum operation_t
{
nominal_glyphs,
@ -79,8 +81,7 @@ _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;
@ -99,12 +100,23 @@ 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;
case CORETEXT:
#ifdef HAVE_CORETEXT
hb_coretext_font_set_funcs (font);
#endif
break;
}
switch (operation)
@ -192,12 +204,23 @@ static void BM_Font (benchmark::State &state,
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;
case CORETEXT:
#ifdef HAVE_CORETEXT
hb_coretext_font_set_funcs (font);
#endif
break;
}
hb_buffer_t *buffer = hb_buffer_create ();
@ -217,7 +240,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 +255,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 +265,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 +272,13 @@ 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
#ifdef HAVE_CORETEXT
test_backend (CORETEXT, "coretext", is_var, op, op_name, time_unit, test_input);
#endif
}
}
}

View file

@ -33,7 +33,6 @@ struct test_input_t
static test_input_t *tests = default_tests;
static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]);
const char *variation = nullptr;
static void BM_Shape (benchmark::State &state,
const char *shaper,
@ -47,13 +46,6 @@ static void BM_Shape (benchmark::State &state,
hb_face_destroy (face);
}
if (variation)
{
hb_variation_t var;
hb_variation_from_string (variation, -1, &var);
hb_font_set_variations (font, &var, 1);
}
hb_blob_t *text_blob = hb_blob_create_from_file_or_fail (input.text_path);
assert (text_blob);
unsigned orig_text_length;
@ -107,16 +99,16 @@ 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].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++)
{
@ -128,4 +120,7 @@ int main(int argc, char** argv)
benchmark::RunSpecifiedBenchmarks();
benchmark::Shutdown();
if (tests != default_tests)
free (tests);
}

View file

@ -36,9 +36,6 @@
#ifdef HAVE_FREETYPE
#include <hb-ft.h>
#endif
#ifdef HAVE_FONTATIONS
#include <hb-fontations.h>
#endif
#ifdef HAVE_CORETEXT
#include <hb-coretext.h>
#endif
@ -56,7 +53,22 @@ 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);
const char *loader = getenv ("HB_FACE_LOADER");
if (loader && !*loader)
loader = nullptr;
#ifdef HAVE_FREETYPE
if (loader && !strcmp (loader, "ft"))
return hb_ft_face_create_from_file_or_fail (font_path, face_index);
#endif
#ifdef HAVE_CORETEXT
if (loader && !strcmp (loader, "coretext"))
return hb_coretext_face_create_from_file_or_fail (font_path, face_index);
#endif
if (!loader || !strcmp (loader, "ot"))
return hb_face_create_from_file_or_fail (font_path, face_index);
assert (false);
}
HB_END_DECLS

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

@ -38,17 +38,3 @@ foreach source : benchmarks_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,
include_directories: [incconfig, incsrc],
link_with: [libharfbuzz],
)
meson.override_find_program('hb-draw-all', hb_draw_all)
hb_paint_all = executable('hb-paint-all', ['hb-paint-all.c'],
cpp_args: cpp_args,
include_directories: [incconfig, incsrc],
link_with: [libharfbuzz],
)
meson.override_find_program('hb-paint-all', hb_paint_all)

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

@ -47,11 +47,6 @@ namespace OT {
struct hb_paint_context_t;
}
struct hb_colr_scratch_t
{
hb_paint_extents_context_t paint_extents;
};
namespace OT {
struct COLR;
@ -95,8 +90,7 @@ public:
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)
font->face->table.CPAL->get_palette_colors (palette_)
#endif
),
foreground (foreground_),
@ -938,9 +932,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);
@ -1517,12 +1511,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 */
@ -2087,8 +2079,6 @@ 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
{
@ -2122,53 +2112,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; }
@ -2204,33 +2148,7 @@ struct COLR
{ 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:
hb_atomic_t<hb_colr_scratch_t *> cached_scratch;
};
void closure_glyphs (hb_codepoint_t glyph,
@ -2602,10 +2520,7 @@ 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
{
ItemVarStoreInstancer instancer (get_var_store_ptr (),
@ -2619,10 +2534,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;
@ -2632,7 +2547,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;
@ -2669,12 +2583,7 @@ struct COLR
#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 (),
@ -2700,7 +2609,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,
@ -2710,16 +2618,15 @@ struct COLR
else
{
auto *extents_funcs = hb_paint_extents_get_funcs ();
scratch.paint_extents.clear ();
hb_paint_extents_context_t extents_data;
paint_glyph (font, glyph,
extents_funcs, &scratch.paint_extents,
extents_funcs, &extents_data,
palette_index, foreground,
false,
scratch);
false);
auto extents = scratch.paint_extents.get_extents ();
is_bounded = scratch.paint_extents.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,
@ -2729,7 +2636,7 @@ struct COLR
}
}
c.funcs->push_font_transform (c.data, font);
c.funcs->push_root_transform (c.data, font);
if (is_bounded)
c.recurse (*paint);
@ -2807,7 +2714,9 @@ void PaintColrLayers::paint_glyph (hb_paint_context_t *c) const
return;
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);
}
}
@ -2819,7 +2728,7 @@ void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const
if (unlikely (!node.visit (gid)))
return;
c->funcs->push_inverse_font_transform (c->data, c->font);
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);

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)

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)

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())
{

View file

@ -126,19 +126,25 @@ 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_decycler_t *decycler,
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
@ -310,18 +313,13 @@ VarComponent::get_path_at (const hb_varc_context_t &c,
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);
total_transform.scale (font->x_mult ? 1.f / font->x_multf : 0.f,
font->y_mult ? 1.f / font->y_multf : 0.f);
bool same_coords = component_coords.length == coords.length &&
component_coords.arrayZ == coords.arrayZ;
c.depth_left--;
VARC.get_path_at (c, gid,
component_coords, total_transform,
VARC.get_path_at (font, gid,
draw_session, component_coords, total_transform,
parent_gid,
same_coords ? cache : nullptr);
c.depth_left++;
decycler, edges_left, depth_left - 1);
}
#undef PROCESS_TRANSFORM_COMPONENTS
@ -331,12 +329,15 @@ VarComponent::get_path_at (const hb_varc_context_t &c,
}
bool
VARC::get_path_at (const hb_varc_context_t &c,
VARC::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_codepoint_t parent_glyph,
VarRegionList::cache_t *parent_cache) const
hb_decycler_t *decycler,
signed *edges_left,
signed depth_left) const
{
// Don't recurse on the same glyph.
unsigned idx = glyph == parent_glyph ?
@ -344,69 +345,50 @@ VARC::get_path_at (const hb_varc_context_t &c,
(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;
// 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,
draw_session.funcs,
draw_session.draw_data,
&draw_session.st};
hb_draw_session_t transformer_session {transformer_funcs, &context};
hb_draw_session_t &shape_draw_session = transform.is_identity () ? draw_session : transformer_session;
if (!c.font->face->table.glyf->get_path_at (c.font, glyph, shape_draw_session, coords, c.scratch.glyf_scratch))
if (!font->face->table.glyf->get_path_at (font, glyph, shape_draw_session, coords))
#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
if (!font->face->table.cff2->get_path_at (font, glyph, shape_draw_session, coords))
if (!font->face->table.cff1->get_path (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 false;
return true;
}
if (c.depth_left <= 0)
if (depth_left <= 0)
return true;
if (c.edges_left <= 0)
if (*edges_left <= 0)
return true;
(c.edges_left)--;
(*edges_left)--;
hb_decycler_node_t node (c.decycler);
hb_decycler_node_t node (*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));
VarRegionList::cache_t *cache = record.length >= 64 ? // Heuristic
(this+varStore).create_cache ()
: nullptr;
transform.scale (c.font->x_multf, c.font->y_multf);
transform.scale (font->x_multf, font->y_multf);
VarCompositeGlyph::get_path_at (c,
glyph,
coords, transform,
VarCompositeGlyph::get_path_at (font, glyph,
draw_session, coords, transform,
record,
decycler, edges_left, depth_left,
cache);
if (cache != parent_cache)
(this+varStore).destroy_cache (cache, hb_array (static_cache));
(this+varStore).destroy_cache (cache);
return true;
}

View file

@ -21,24 +21,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 +44,39 @@ 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_decycler_t *decycler,
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_decycler_t *decycler,
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, transform,
record,
cache);
decycler, edges_left, depth_left, cache);
}
}
};
@ -101,48 +90,31 @@ 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,
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_TRANSFORM_IDENTITY,
hb_codepoint_t parent_gid = HB_CODEPOINT_INVALID,
VarRegionList::cache_t *parent_cache = nullptr) const;
hb_transform_t transform,
hb_codepoint_t parent_glyph,
hb_decycler_t *decycler,
signed *edges_left,
signed depth_left) 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 (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const
{
hb_varc_context_t c {font,
&draw_session,
nullptr,
hb_decycler_t {},
HB_MAX_GRAPH_EDGE_COUNT,
HB_MAX_NESTING_LEVEL,
scratch};
hb_decycler_t decycler;
signed edges = HB_MAX_GRAPH_EDGE_COUNT;
return get_path_at (c, gid,
hb_array (font->coords, font->num_coords));
}
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};
return get_path_at (c, gid,
hb_array (font->coords, font->num_coords));
}
return get_path_at (font,
gid,
draw_session,
hb_array (font->coords, font->num_coords),
HB_TRANSFORM_IDENTITY,
HB_CODEPOINT_INVALID,
&decycler,
&edges,
HB_MAX_NESTING_LEVEL); }
bool sanitize (hb_sanitize_context_t *c) const
{
@ -157,89 +129,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;
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 +140,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_exact (points.length + num_points + 4); // 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)

View file

@ -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;
@ -380,12 +372,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 +392,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,29 +414,13 @@ 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);
}
@ -486,52 +455,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 +475,6 @@ struct glyf_accelerator_t
unsigned int num_glyphs;
hb_blob_ptr_t<loca> loca_table;
hb_blob_ptr_t<glyf> glyf_table;
hb_atomic_t<hb_glyf_scratch_t *> cached_scratch;
};

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

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,26 +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::.*'
'_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
@ -42,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

@ -21,10 +21,6 @@ if '--experimental-api' not in sys.argv:
experimental_symbols = \
"""hb_shape_justify
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

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

@ -57,8 +57,6 @@
#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.cc"

View file

@ -8,9 +8,6 @@
#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"

View file

@ -29,8 +29,6 @@
#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"
@ -50,61 +48,6 @@ 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,11 +64,10 @@ 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;
hb_bit_set_t buffer_glyph_set;
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;
@ -148,15 +90,15 @@ struct hb_aat_apply_context_t :
void setup_buffer_glyph_set ()
{
using_buffer_glyph_set = buffer->len >= 4 && buffer_glyph_set;
using_buffer_glyph_set = buffer->len >= 4;
if (likely (using_buffer_glyph_set))
buffer->collect_codepoints (*buffer_glyph_set);
if (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);
if (using_buffer_glyph_set)
return buffer_glyph_set.intersects (*machine_glyph_set);
// Faster for shorter buffers.
for (unsigned i = 0; i < buffer->len; i++)
@ -164,69 +106,6 @@ struct hb_aat_apply_context_t :
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 +113,8 @@ struct hb_aat_apply_context_t :
* Lookup Table
*/
enum { DELETED_GLYPH = 0xFFFF };
template <typename T> struct Lookup;
template <typename T>
@ -298,7 +179,6 @@ struct LookupSegmentSingle
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;
glyphs.add_range (first, last);
}
@ -388,7 +268,6 @@ struct LookupSegmentArray
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]))
@ -489,7 +368,6 @@ struct LookupSingle
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;
glyphs.add (glyph);
}
@ -868,10 +746,6 @@ struct StateTable
}
// And glyphs in those classes.
if (filter (CLASS_DELETED_GLYPH))
glyphs.add (DELETED_GLYPH);
(this+classTable).collect_glyphs_filtered (glyphs, num_glyphs, filter);
}

View file

@ -185,9 +185,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; }
@ -328,9 +325,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
@ -398,8 +394,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:
@ -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:
@ -921,18 +921,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_bit_set_t, hb_bit_set_t>>;
template <typename T>
struct KerxTable
@ -996,8 +985,6 @@ struct KerxTable
{
c->buffer->unsafe_to_concat ();
c->setup_buffer_glyph_set ();
typedef typename T::SubTable SubTable;
bool ret = false;
@ -1009,25 +996,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 +1028,9 @@ struct KerxTable
if (reverse)
c->buffer->reverse ();
c->left_set = &accel_data[i].first;
c->right_set = &accel_data[i].second;
{
/* See comment in sanitize() for conditional here. */
hb_sanitize_with_object_t with (&c->sanitizer, i < count - 1 ? st : (const SubTable *) nullptr);
@ -1129,13 +1106,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_bit_set_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);
}
@ -1164,7 +1137,6 @@ struct KerxTable
hb_blob_ptr_t<T> table;
kern_accelerator_data_t accel_data;
hb_aat_scratch_t scratch;
};
};

View file

@ -30,6 +30,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"
/*
@ -176,6 +178,12 @@ struct RearrangementSubtable
StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
if (!c->buffer_intersects_machine ())
{
(void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches");
return_trace (false);
}
driver.drive (&dc, c);
return_trace (dc.ret);
@ -234,7 +242,9 @@ struct ContextualSubtable
ret (false),
c (c_),
table (table_),
gdef (*c->gdef_table),
mark_set (false),
has_glyph_classes (gdef.has_glyph_classes ()),
mark (0),
subs (table+table->substitutionTables) {}
@ -271,7 +281,12 @@ struct ContextualSubtable
if (replacement)
{
buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len));
c->replace_glyph_inplace (mark, *replacement);
hb_codepoint_t glyph = *replacement;
buffer->info[mark].codepoint = glyph;
c->buffer_glyph_set.add (glyph);
if (has_glyph_classes)
_hb_glyph_info_set_glyph_props (&buffer->info[mark],
gdef.get_glyph_props (*replacement));
ret = true;
}
@ -297,7 +312,12 @@ struct ContextualSubtable
}
if (replacement)
{
c->replace_glyph_inplace (idx, *replacement);
hb_codepoint_t glyph = *replacement;
buffer->info[idx].codepoint = glyph;
c->buffer_glyph_set.add (glyph);
if (has_glyph_classes)
_hb_glyph_info_set_glyph_props (&buffer->info[idx],
gdef.get_glyph_props (*replacement));
ret = true;
}
@ -313,7 +333,9 @@ struct ContextualSubtable
hb_aat_apply_context_t *c;
const ContextualSubtable *table;
private:
const OT::GDEF &gdef;
bool mark_set;
bool has_glyph_classes;
unsigned int mark;
const UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, void, false> &subs;
};
@ -326,6 +348,12 @@ struct ContextualSubtable
StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
if (!c->buffer_intersects_machine ())
{
(void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches");
return_trace (false);
}
driver.drive (&dc, c);
return_trace (dc.ret);
@ -553,7 +581,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 +589,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;
_hb_glyph_info_set_default_ignorable (&buffer->cur());
if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return;
}
if (unlikely (!buffer->move_to (lig_end))) return;
@ -595,6 +624,12 @@ struct LigatureSubtable
StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
if (!c->buffer_intersects_machine ())
{
(void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches");
return_trace (false);
}
driver.drive (&dc, c);
return_trace (dc.ret);
@ -630,6 +665,15 @@ struct NoncontextualSubtable
{
TRACE_APPLY (this);
if (!c->buffer_intersects_machine ())
{
(void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches");
return_trace (false);
}
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 +703,12 @@ struct NoncontextualSubtable
const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
if (replacement)
{
c->replace_glyph_inplace (i, *replacement);
hb_codepoint_t glyph = *replacement;
info[i].codepoint = glyph;
c->buffer_glyph_set.add (glyph);
if (has_glyph_classes)
_hb_glyph_info_set_glyph_props (&info[i],
gdef.get_glyph_props (*replacement));
ret = true;
}
}
@ -801,7 +850,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_glyph_set.add (glyphs[i]);
ret = true;
if (buffer->idx < buffer->len && !before)
buffer->skip_glyph ();
@ -830,8 +881,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 ();
@ -871,6 +921,12 @@ struct InsertionSubtable
StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
if (!c->buffer_intersects_machine ())
{
(void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches");
return_trace (false);
}
driver.drive (&dc, c);
return_trace (dc.ret);
@ -1168,7 +1224,6 @@ struct Chain
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); })))
goto skip;
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;
@ -1178,12 +1233,6 @@ struct Chain
bool (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.
@ -1327,7 +1376,7 @@ struct mortmorx
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;
@ -1374,8 +1423,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;
};

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
@ -116,7 +115,7 @@ struct TrackTableEntry
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>>
@ -143,9 +142,9 @@ struct TrackData
unsigned j = count - 1;
// Find the two entries that track is between.
while (i + 1 < count && trackTable[i + 1].get_track_value () <= track)
while (i + 1 < count && trackTable[i + 1].get_track_value () < track)
i++;
while (j > 0 && trackTable[j - 1].get_track_value () >= track)
while (j > 0 && trackTable[j - 1].get_track_value () > track)
j--;
// Exact match.
@ -201,46 +200,6 @@ struct trak
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
{
TRACE_APPLY (this);
float ptem = c->font->ptem;
if (unlikely (ptem <= 0.f))
{
/* https://developer.apple.com/documentation/coretext/1508745-ctfontcreatewithgraphicsfont */
ptem = HB_CORETEXT_DEFAULT_FONT_SIZE;
}
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);
foreach_grapheme (buffer, start, end)
buffer->pos[start].x_advance += advance_to_add;
}
else
{
hb_position_t advance_to_add = get_v_tracking (c->font, track);
foreach_grapheme (buffer, start, end)
buffer->pos[start].y_advance += advance_to_add;
}
return_trace (true);
}
bool sanitize (hb_sanitize_context_t *c) const
{

View file

@ -34,7 +34,7 @@
#include "hb-aat-layout-just-table.hh" // Just so we compile it; unused otherwise.
#include "hb-aat-layout-kerx-table.hh"
#include "hb-aat-layout-morx-table.hh"
#include "hb-aat-layout-trak-table.hh"
#include "hb-aat-layout-trak-table.hh" // Just so we compile it; unused otherwise.
#include "hb-aat-ltag-table.hh"
#include "hb-ot-layout-gsub-table.hh"
@ -58,14 +58,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,7 +203,7 @@ hb_aat_layout_find_feature_mapping (hb_tag_t tag)
#endif
#ifndef HB_NO_AAT_SHAPE
#ifndef HB_NO_AAT
/*
* mort/morx/kerx/trak
@ -288,14 +287,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 +300,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 +313,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 +371,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");
}
@ -394,17 +394,6 @@ hb_aat_layout_has_tracking (hb_face_t *face)
return face->table.trak->has_data ();
}
void
hb_aat_layout_track (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
const AAT::trak& trak = *font->face->table.trak;
AAT::hb_aat_apply_context_t c (plan, font, buffer);
trak.apply (&c);
}
/**
* hb_aat_layout_get_feature_types:
* @face: #hb_face_t to work upon

View file

@ -60,6 +60,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);
@ -68,10 +71,5 @@ hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
HB_INTERNAL void
hb_aat_layout_track (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
#endif /* HB_AAT_LAYOUT_HH */

View file

@ -85,11 +85,6 @@ 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;

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,47 +149,62 @@ 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_); }

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,7 +88,7 @@ struct hb_bit_set_t
{
if (unlikely (!successful)) return false;
if (pages.length < count && (unsigned) pages.allocated < count && count <= 2)
if (pages.length < count && count <= 2)
exact_size = true; // Most sets are small and local
if (unlikely (!pages.resize (count, clear, exact_size) ||

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 */

File diff suppressed because it is too large Load diff

View file

@ -91,8 +91,6 @@ yoffset = "\"dy\"" colon (num >tok %parse_y_offset);
xadvance= "\"ax\"" colon (num >tok %parse_x_advance);
yadvance= "\"ay\"" colon (num >tok %parse_y_advance);
glyphflags="\"fl\"" colon (unum >tok %parse_glyph_flags);
# Not parsed. Ignored.
glyphextents="\""("xb"|"yb"|"w"|"h")"\"" colon (num >tok);
element = glyph @ensure_glyphs
| unicode @ensure_unicode
@ -101,16 +99,14 @@ element = glyph @ensure_glyphs
| yoffset
| xadvance
| yadvance
| glyphflags
| glyphextents
;
| glyphflags;
item =
( '{' space* element (comma element)* space* '}' space* (','|']') space* )
( '{' space* element (comma element)* space* '}')
>clear_item
@add_item
;
main := space* '['? space* item*;
main := space* '['? space* item (comma item)* space* (','|']')?;
}%%
@ -137,7 +133,7 @@ _hb_buffer_deserialize_json (hb_buffer_t *buffer,
*end_ptr = p;
return p == pe;
return p == pe && *(p-1) != ']';
}
#endif /* HB_BUFFER_DESERIALIZE_JSON_HH */

File diff suppressed because it is too large Load diff

View file

@ -41,9 +41,10 @@ action clear_item {
}
action add_item {
buffer->add_info_and_pos (info, pos);
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
@ -76,9 +77,7 @@ glyph = (glyph_id | glyph_name) >tok %parse_glyph;
cluster = '=' (unum >tok %parse_cluster);
offsets = '@' (num >tok %parse_x_offset) ',' (num >tok %parse_y_offset );
advances= '+' (num >tok %parse_x_advance) (',' (num >tok %parse_y_advance))?;
glyphflags = '#' (unum >tok %parse_glyph_flags);
# Not parsed. Ignored.
glyphextents = '<' (num ',' num ',' num ',' num) '>';
glyphflags= '#' (unum >tok %parse_glyph_flags);
glyph_item =
(
@ -87,16 +86,14 @@ glyph_item =
offsets?
advances?
glyphflags?
glyphextents?
( '|' | ']')
)
>clear_item
%add_item
;
glyphs = '['? glyph_item* ;
glyphs = glyph_item (space* '|' space* glyph_item)* space*;
main := glyphs;
main := space* glyphs;
}%%
@ -107,11 +104,28 @@ _hb_buffer_deserialize_text_glyphs (hb_buffer_t *buffer,
const char **end_ptr,
hb_font_t *font)
{
const char *p = buf, *pe = buf + buf_len, *eof = pe;
const char *p = buf, *pe = buf + buf_len, *eof = pe, *orig_pe = pe;
/* Ensure we have positions. */
(void) hb_buffer_get_glyph_positions (buffer, nullptr);
while (p < pe && ISSPACE (*p))
p++;
if (p < pe && *p == (buffer->len ? '|' : '['))
*end_ptr = ++p;
const char *end = strchr ((char *) p, ']');
if (end)
pe = eof = end;
else
{
end = strrchr ((char *) p, '|');
if (end)
pe = eof = end;
else
pe = eof = p;
}
const char *tok = nullptr;
int cs;
hb_glyph_info_t info = {0};
@ -121,6 +135,13 @@ _hb_buffer_deserialize_text_glyphs (hb_buffer_t *buffer,
write exec;
}%%
if (pe < orig_pe && *pe == ']')
{
pe++;
if (p == pe)
p++;
}
*end_ptr = p;
return p == pe;

View file

@ -34,106 +34,135 @@
#line 36 "hb-buffer-deserialize-text-unicode.hh"
static const unsigned char _deserialize_text_unicode_trans_keys[] = {
0u, 0u, 43u, 102u, 48u, 102u, 48u, 124u, 48u, 57u, 62u, 124u, 48u, 124u, 60u, 117u,
85u, 117u, 85u, 117u, 0
0u, 0u, 9u, 117u, 43u, 102u, 48u, 102u, 48u, 57u, 9u, 124u, 9u, 124u, 9u, 124u,
9u, 124u, 0
};
static const char _deserialize_text_unicode_key_spans[] = {
0, 60, 55, 77, 10, 63, 77, 58,
33, 33
0, 109, 60, 55, 10, 116, 116, 116,
116
};
static const short _deserialize_text_unicode_index_offsets[] = {
0, 0, 61, 117, 195, 206, 270, 348,
407, 441
0, 0, 110, 171, 227, 238, 355, 472,
589
};
static const char _deserialize_text_unicode_indicies[] = {
0, 1, 1, 1, 1, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 2,
2, 2, 2, 2, 2, 1, 1, 1,
0, 0, 0, 0, 0, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 2,
2, 2, 2, 2, 2, 1, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 2,
2, 2, 2, 2, 2, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 2,
2, 2, 2, 2, 2, 1, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
1, 1, 1, 4, 5, 1, 1, 3,
3, 3, 3, 3, 3, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 3,
3, 3, 3, 3, 3, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 5, 1, 6, 7, 7, 7,
7, 7, 7, 7, 7, 7, 1, 8,
0, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 8, 1, 9,
9, 9, 9, 9, 9, 9, 9, 9,
9, 1, 1, 1, 1, 8, 1, 1,
1, 1, 1, 1, 1, 2, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 2, 1, 3,
1, 1, 1, 1, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 1, 1,
1, 1, 1, 1, 1, 4, 4, 4,
4, 4, 4, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 4, 4, 4,
4, 4, 4, 1, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 1, 1,
1, 1, 1, 1, 1, 4, 4, 4,
4, 4, 4, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 8, 1, 10, 1, 1,
1, 1, 1, 1, 1, 4, 4, 4,
4, 4, 4, 1, 5, 6, 6, 6,
6, 6, 6, 6, 6, 6, 1, 7,
7, 7, 7, 7, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 7, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8,
1, 1, 1, 9, 1, 1, 1, 8,
8, 8, 8, 8, 8, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 11, 1,
1, 1, 1, 1, 1, 1, 1, 8,
8, 8, 8, 8, 8, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 11, 1,
1, 1, 10, 1, 11, 11, 11, 11,
11, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
11, 1, 12, 1, 1, 1, 1, 1,
1, 1, 1, 11, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 12, 1, 0
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 0,
1, 12, 12, 12, 12, 12, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
12, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 13, 1, 12, 12,
12, 12, 12, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 12, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 13, 1, 0
};
static const char _deserialize_text_unicode_trans_targs[] = {
2, 0, 3, 3, 4, 9, 5, 6,
9, 6, 8, 1, 1
1, 0, 2, 3, 5, 7, 8, 6,
5, 4, 1, 6, 6, 1, 8
};
static const char _deserialize_text_unicode_trans_actions[] = {
0, 0, 1, 0, 2, 2, 1, 1,
3, 0, 0, 4, 6
0, 0, 1, 0, 2, 2, 2, 3,
0, 4, 3, 0, 5, 5, 0
};
static const char _deserialize_text_unicode_eof_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 5
0, 0, 0, 0, 0, 3, 0, 5,
5
};
static const int deserialize_text_unicode_start = 7;
static const int deserialize_text_unicode_first_final = 7;
static const int deserialize_text_unicode_start = 1;
static const int deserialize_text_unicode_first_final = 5;
static const int deserialize_text_unicode_error = 0;
static const int deserialize_text_unicode_en_main = 7;
static const int deserialize_text_unicode_en_main = 1;
#line 80 "hb-buffer-deserialize-text-unicode.rl"
#line 79 "hb-buffer-deserialize-text-unicode.rl"
static hb_bool_t
@ -143,19 +172,37 @@ _hb_buffer_deserialize_text_unicode (hb_buffer_t *buffer,
const char **end_ptr,
hb_font_t *font)
{
const char *p = buf, *pe = buf + buf_len, *eof = pe;
const char *p = buf, *pe = buf + buf_len, *eof = pe, *orig_pe = pe;
while (p < pe && ISSPACE (*p))
p++;
if (p < pe && *p == (buffer->len ? '|' : '<'))
*end_ptr = ++p;
const char *end = strchr ((char *) p, '>');
if (end)
pe = eof = end;
else
{
end = strrchr ((char *) p, '|');
if (end)
pe = eof = end;
else
pe = eof = p;
}
const char *tok = nullptr;
int cs;
hb_glyph_info_t info = {0};
const hb_glyph_position_t pos = {0};
#line 154 "hb-buffer-deserialize-text-unicode.hh"
#line 201 "hb-buffer-deserialize-text-unicode.hh"
{
cs = deserialize_text_unicode_start;
}
#line 159 "hb-buffer-deserialize-text-unicode.hh"
#line 206 "hb-buffer-deserialize-text-unicode.hh"
{
int _slen;
int _trans;
@ -180,27 +227,25 @@ _resume:
goto _again;
switch ( _deserialize_text_unicode_trans_actions[_trans] ) {
case 4:
case 1:
#line 38 "hb-buffer-deserialize-text-unicode.rl"
{
hb_memset (&info, 0, sizeof (info));
}
break;
case 1:
case 2:
#line 51 "hb-buffer-deserialize-text-unicode.rl"
{
tok = p;
}
break;
case 2:
case 4:
#line 55 "hb-buffer-deserialize-text-unicode.rl"
{if (!parse_hex (tok, p, &info.codepoint )) return false; }
break;
case 3:
#line 57 "hb-buffer-deserialize-text-unicode.rl"
{ if (!parse_uint (tok, p, &info.cluster )) return false; }
break;
case 6:
#line 55 "hb-buffer-deserialize-text-unicode.rl"
{if (!parse_hex (tok, p, &info.codepoint )) return false; }
#line 42 "hb-buffer-deserialize-text-unicode.rl"
{
buffer->add_info (info);
@ -210,12 +255,21 @@ _resume:
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
#line 38 "hb-buffer-deserialize-text-unicode.rl"
break;
case 5:
#line 57 "hb-buffer-deserialize-text-unicode.rl"
{ if (!parse_uint (tok, p, &info.cluster )) return false; }
#line 42 "hb-buffer-deserialize-text-unicode.rl"
{
hb_memset (&info, 0, sizeof (info));
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
if (buffer->have_positions)
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
#line 219 "hb-buffer-deserialize-text-unicode.hh"
#line 273 "hb-buffer-deserialize-text-unicode.hh"
}
_again:
@ -227,7 +281,9 @@ _again:
if ( p == eof )
{
switch ( _deserialize_text_unicode_eof_actions[cs] ) {
case 5:
case 3:
#line 55 "hb-buffer-deserialize-text-unicode.rl"
{if (!parse_hex (tok, p, &info.codepoint )) return false; }
#line 42 "hb-buffer-deserialize-text-unicode.rl"
{
buffer->add_info (info);
@ -238,16 +294,36 @@ _again:
*end_ptr = p;
}
break;
#line 242 "hb-buffer-deserialize-text-unicode.hh"
case 5:
#line 57 "hb-buffer-deserialize-text-unicode.rl"
{ if (!parse_uint (tok, p, &info.cluster )) return false; }
#line 42 "hb-buffer-deserialize-text-unicode.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
if (buffer->have_positions)
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
#line 311 "hb-buffer-deserialize-text-unicode.hh"
}
}
_out: {}
}
#line 98 "hb-buffer-deserialize-text-unicode.rl"
#line 115 "hb-buffer-deserialize-text-unicode.rl"
if (pe < orig_pe && *pe == '>')
{
pe++;
if (p == pe)
p++;
}
*end_ptr = p;
return p == pe;

View file

@ -67,15 +67,14 @@ unicode_item =
(
unicode
cluster?
('|' | '>')
)
>clear_item
%add_item
;
unicodes = '<'? unicode_item*;
unicodes = unicode_item (space* '|' space* unicode_item)* space*;
main := unicodes;
main := space* unicodes;
}%%
@ -86,7 +85,25 @@ _hb_buffer_deserialize_text_unicode (hb_buffer_t *buffer,
const char **end_ptr,
hb_font_t *font)
{
const char *p = buf, *pe = buf + buf_len, *eof = pe;
const char *p = buf, *pe = buf + buf_len, *eof = pe, *orig_pe = pe;
while (p < pe && ISSPACE (*p))
p++;
if (p < pe && *p == (buffer->len ? '|' : '<'))
*end_ptr = ++p;
const char *end = strchr ((char *) p, '>');
if (end)
pe = eof = end;
else
{
end = strrchr ((char *) p, '|');
if (end)
pe = eof = end;
else
pe = eof = p;
}
const char *tok = nullptr;
int cs;
@ -97,6 +114,13 @@ _hb_buffer_deserialize_text_unicode (hb_buffer_t *buffer,
write exec;
}%%
if (pe < orig_pe && *pe == '>')
{
pe++;
if (p == pe)
p++;
}
*end_ptr = p;
return p == pe;

View file

@ -169,13 +169,11 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
{
hb_glyph_extents_t extents;
if (hb_font_get_glyph_extents(font, info[i].codepoint, &extents))
{
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
extents.x_bearing, extents.y_bearing));
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
extents.width, extents.height));
}
hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
extents.x_bearing, extents.y_bearing));
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
extents.width, extents.height));
}
*p++ = '}';
@ -320,8 +318,8 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
{
hb_glyph_extents_t extents;
if (hb_font_get_glyph_extents(font, info[i].codepoint, &extents))
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
}
if (i == end-1) {
@ -739,7 +737,8 @@ parse_hex (const char *pp, const char *end, uint32_t *pv)
* Deserializes glyphs @buffer from textual representation in the format
* produced by hb_buffer_serialize_glyphs().
*
* Return value: `true` if the full string was parsed, `false` otherwise.
* Return value: `true` if parse was successful, `false` if an error
* occurred.
*
* Since: 0.9.7
**/
@ -811,7 +810,8 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
* Deserializes Unicode @buffer from textual representation in the format
* produced by hb_buffer_serialize_unicode().
*
* Return value: `true` if the full string was parsed, `false` otherwise.
* Return value: `true` if parse was successful, `false` if an error
* occurred.
*
* Since: 2.7.3
**/

View file

@ -63,25 +63,24 @@ static bool
buffer_verify_monotone (hb_buffer_t *buffer,
hb_font_t *font)
{
if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (buffer->cluster_level))
/* Check that clusters are monotone. */
if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES ||
buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
{
/* Cannot perform this check without monotone clusters. */
return true;
bool is_forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));
unsigned int num_glyphs;
hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
for (unsigned int i = 1; i < num_glyphs; i++)
if (info[i-1].cluster != info[i].cluster &&
(info[i-1].cluster < info[i].cluster) != is_forward)
{
buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "clusters are not monotone.");
return false;
}
}
bool is_forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));
unsigned int num_glyphs;
hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
for (unsigned int i = 1; i < num_glyphs; i++)
if (info[i-1].cluster != info[i].cluster &&
(info[i-1].cluster < info[i].cluster) != is_forward)
{
buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "clusters are not monotone.");
return false;
}
return true;
}
@ -93,7 +92,8 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer,
unsigned int num_features,
const char * const *shapers)
{
if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (buffer->cluster_level))
if (buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES &&
buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
{
/* Cannot perform this check without monotone clusters. */
return true;
@ -207,7 +207,8 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer,
unsigned int num_features,
const char * const *shapers)
{
if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (buffer->cluster_level))
if (buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES &&
buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
{
/* Cannot perform this check without monotone clusters. */
return true;

View file

@ -370,18 +370,6 @@ hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info)
len++;
}
void
hb_buffer_t::add_info_and_pos (const hb_glyph_info_t &glyph_info,
const hb_glyph_position_t &glyph_pos)
{
if (unlikely (!ensure (len + 1))) return;
info[len] = glyph_info;
assert (have_positions);
pos[len] = glyph_pos;
len++;
}
void
@ -530,7 +518,7 @@ void
hb_buffer_t::merge_clusters_impl (unsigned int start,
unsigned int end)
{
if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (cluster_level))
if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
{
unsafe_to_break (start, end);
return;
@ -563,7 +551,7 @@ void
hb_buffer_t::merge_out_clusters (unsigned int start,
unsigned int end)
{
if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (cluster_level))
if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
return;
if (unlikely (end - start < 2))

View file

@ -422,34 +422,18 @@ hb_buffer_get_flags (const hb_buffer_t *buffer);
* @HB_BUFFER_CLUSTER_LEVEL_CHARACTERS: Don't group cluster values.
* @HB_BUFFER_CLUSTER_LEVEL_DEFAULT: Default cluster level,
* equal to @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES.
* @HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES: Only group clusters, but don't enforce monotone order.
*
*
* Data type for holding HarfBuzz's clustering behavior options. The cluster level
* dictates one aspect of how HarfBuzz will treat non-base characters
* dictates one aspect of how HarfBuzz will treat non-base characters
* during shaping.
*
* In @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES, non-base
* characters are merged into the cluster of the base character that precedes them.
* There is also cluster merging every time the clusters will otherwise become non-monotone.
*
* In @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS, non-base characters are initially
* assigned their own cluster values, which are not merged into preceding base
* clusters. This allows HarfBuzz to perform additional operations like reorder
* sequences of adjacent marks. The output is still monotone, but the cluster
* values are more granular.
*
* In @HB_BUFFER_CLUSTER_LEVEL_CHARACTERS, non-base characters are assigned their
* own cluster values, which are not merged into preceding base clusters. Moreover,
* the cluster values are not merged into monotone order. This is the most granular
* cluster level, and it is useful for clients that need to know the exact cluster
* values of each character, but is harder to use for clients, since clusters
* might appear in any order.
*
* In @HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES, non-base characters are merged into the
* cluster of the base character that precedes them. This is similar to the Unicode
* Grapheme Cluster algorithm, but it is not exactly the same. The output is
* not forced to be monotone. This is useful for clients that want to use HarfBuzz
* as a cheap implementation of the Unicode Grapheme Cluster algorithm.
* sequences of adjacent marks.
*
* @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES is the default, because it maintains
* backward compatibility with older versions of HarfBuzz. New client programs that
@ -462,52 +446,9 @@ typedef enum {
HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES = 0,
HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS = 1,
HB_BUFFER_CLUSTER_LEVEL_CHARACTERS = 2,
HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES = 3,
HB_BUFFER_CLUSTER_LEVEL_DEFAULT = HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES
} hb_buffer_cluster_level_t;
/**
* HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE:
* @level: #hb_buffer_cluster_level_t to test
*
* Tests whether a cluster level groups cluster values into monotone order.
* Requires that the level be valid.
*
* Since: 11.0.0
*/
#define HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE(level) \
((bool) ((1u << (unsigned) (level)) & \
((1u << HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES) | \
(1u << HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS))))
/**
* HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES:
* @level: #hb_buffer_cluster_level_t to test
*
* Tests whether a cluster level groups cluster values by graphemes. Requires
* that the level be valid.
*
* Since: 11.0.0
*/
#define HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES(level) \
((bool) ((1u << (unsigned) (level)) & \
((1u << HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES) | \
(1u << HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES))))
/**
* HB_BUFFER_CLUSTER_LEVEL_IS_CHARACTERS
* @level: #hb_buffer_cluster_level_t to test
*
* Tests whether a cluster level does not group cluster values by graphemes.
* Requires that the level be valid.
*
* Since: 11.0.0
*/
#define HB_BUFFER_CLUSTER_LEVEL_IS_CHARACTERS(level) \
((bool) ((1u << (unsigned) (level)) & \
((1u << HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARCATERS) | \
(1u << HB_BUFFER_CLUSTER_LEVEL_CHARACTERS))))
HB_EXTERN void
hb_buffer_set_cluster_level (hb_buffer_t *buffer,
hb_buffer_cluster_level_t cluster_level);

View file

@ -229,8 +229,6 @@ struct hb_buffer_t
HB_INTERNAL void add (hb_codepoint_t codepoint,
unsigned int cluster);
HB_INTERNAL void add_info (const hb_glyph_info_t &glyph_info);
HB_INTERNAL void add_info_and_pos (const hb_glyph_info_t &glyph_info,
const hb_glyph_position_t &glyph_pos);
void reverse_range (unsigned start, unsigned end)
{

View file

@ -30,31 +30,18 @@
#include "hb.hh"
/* Implements a lockfree and thread-safe cache for int->int functions,
* using (optionally) _relaxed_ atomic integer operations.
/* Implements a lockfree cache for int->int functions.
*
* The cache is a fixed-size array of 16-bit or 32-bit integers,
* typically 256 elements.
* The cache is a fixed-size array of 16-bit or 32-bit integers.
* The key is split into two parts: the cache index and the rest.
*
* The key is split into two parts: the cache index (high bits)
* and the rest (low bits).
*
* The cache index is used to index into the array. The array
* member is a 16-bit or 32-bit integer that is used *both*
* to store the low bits of the key, and the value.
* The cache index is used to index into the array. The rest is used
* to store the key and the value.
*
* The value is stored in the least significant bits of the integer.
* The low bits of the key are stored in the most significant bits
* of the integer.
*
* A cache hit is detected by comparing the low bits of the key
* with the high bits of the integer at the array position indexed
* by the high bits of the key. If they match, the value is extracted
* from the least significant bits of the integer and returned.
* Otherwise, a cache miss is reported.
*
* Cache operations (storage and retrieval) involve just a few
* arithmetic operations and a single memory access.
* The key is stored in the most significant bits of the integer.
* The key is shifted by cache_bits to the left to make room for the
* value.
*/
template <unsigned int key_bits=16,
@ -65,11 +52,11 @@ struct hb_cache_t
{
using item_t = typename std::conditional<thread_safe,
typename std::conditional<key_bits + value_bits - cache_bits <= 16,
hb_atomic_t<unsigned short>,
hb_atomic_t<unsigned int>>::type,
hb_atomic_short_t,
hb_atomic_int_t>::type,
typename std::conditional<key_bits + value_bits - cache_bits <= 16,
unsigned short,
unsigned int>::type
short,
int>::type
>::type;
static_assert ((key_bits >= cache_bits), "");

View file

@ -726,9 +726,6 @@ _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops,
float span;
span = angles[n_stops - 1] - angles[0];
if (!span)
goto done;
k = 0;
if (angles[0] >= 0)
{

View file

@ -71,8 +71,7 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
template <typename ACC>
cff2_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd,
const int *coords_=nullptr, unsigned int num_coords_=0)
: SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs),
cached_scalars_vector (&acc.cached_scalars_vector)
: SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs)
{
coords = coords_;
num_coords = num_coords_;
@ -81,39 +80,9 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
set_ivs (acc.privateDicts[fd].ivs);
}
~cff2_cs_interp_env_t ()
void fini ()
{
release_scalars_vector (scalars);
}
hb_vector_t<float> *acquire_scalars_vector () const
{
hb_vector_t<float> *scalars = cached_scalars_vector->get_acquire ();
if (!scalars || !cached_scalars_vector->cmpexch (scalars, nullptr))
{
scalars = (hb_vector_t<float> *) hb_calloc (1, sizeof (hb_vector_t<float>));
if (unlikely (!scalars))
return nullptr;
scalars->init ();
}
return scalars;
}
void release_scalars_vector (hb_vector_t<float> *scalars) const
{
if (!scalars)
return;
scalars->clear ();
if (!cached_scalars_vector->cmpexch (nullptr, scalars))
{
scalars->fini ();
hb_free (scalars);
}
scalars = nullptr;
SUPER::fini ();
}
op_code_t fetch_op ()
@ -142,20 +111,14 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
{
if (!seen_blend)
{
scalars = acquire_scalars_vector ();
if (unlikely (!scalars))
SUPER::set_error ();
else
region_count = varStore->varStore.get_region_index_count (get_ivs ());
if (do_blend)
{
region_count = varStore->varStore.get_region_index_count (get_ivs ());
if (do_blend)
{
if (unlikely (!scalars->resize_exact (region_count)))
SUPER::set_error ();
else
varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords,
&(*scalars)[0], region_count);
}
if (unlikely (!scalars.resize_exact (region_count)))
SUPER::set_error ();
else
varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords,
&scalars[0], region_count);
}
seen_blend = true;
}
@ -186,11 +149,11 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
double v = 0;
if (do_blend)
{
if (likely (scalars && scalars->length == deltas.length))
if (likely (scalars.length == deltas.length))
{
unsigned count = scalars->length;
unsigned count = scalars.length;
for (unsigned i = 0; i < count; i++)
v += (double) scalars->arrayZ[i] * deltas.arrayZ[i].to_real ();
v += (double) scalars.arrayZ[i] * deltas.arrayZ[i].to_real ();
}
}
return v;
@ -204,8 +167,7 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
const CFF2ItemVariationStore *varStore;
unsigned int region_count;
unsigned int ivs;
hb_vector_t<float> *scalars = nullptr;
hb_atomic_t<hb_vector_t<float> *> *cached_scalars_vector = nullptr;
hb_vector_t<float> scalars;
bool do_blend;
bool seen_vsindex_ = false;
bool seen_blend = false;

View file

@ -42,7 +42,7 @@
/* hb_options_t */
hb_atomic_t<unsigned> _hb_options;
hb_atomic_int_t _hb_options;
void
_hb_options_init ()
@ -273,7 +273,7 @@ struct hb_language_item_t {
/* Thread-safe lockfree language list */
static hb_atomic_t<hb_language_item_t *> langs;
static hb_atomic_ptr_t <hb_language_item_t> langs;
static inline void
free_langs ()
@ -403,7 +403,7 @@ hb_language_to_string (hb_language_t language)
hb_language_t
hb_language_get_default ()
{
static hb_atomic_t<hb_language_t> default_language;
static hb_atomic_ptr_t <hb_language_t> default_language;
hb_language_t language = default_language;
if (unlikely (language == HB_LANGUAGE_INVALID))
@ -968,9 +968,6 @@ hb_feature_from_string (const char *str, int len,
* understood by hb_feature_from_string(). The client in responsible for
* allocating big enough size for @buf, 128 bytes is more than enough.
*
* Note that the feature value will be omitted if it is '1', but the
* string won't include any whitespace.
*
* Since: 0.9.5
**/
void
@ -1124,8 +1121,6 @@ get_C_locale ()
* understood by hb_variation_from_string(). The client in responsible for
* allocating big enough size for @buf, 128 bytes is more than enough.
*
* Note that the string won't include any whitespace.
*
* Since: 1.4.2
*/
void
@ -1217,58 +1212,6 @@ uint8_t
return hb_color_get_blue (color);
}
/**
* hb_malloc:
* @size: The size of the memory to allocate.
*
* Allocates @size bytes of memory, using the allocator set at
* compile-time. Typically just malloc().
*
* Return value: A pointer to the allocated memory.
*
* Since: 11.0.0
**/
void* hb_malloc(size_t size) { return hb_malloc_impl (size); }
/**
* hb_calloc:
* @nmemb: The number of elements to allocate.
* @size: The size of each element.
*
* Allocates @nmemb elements of @size bytes each, initialized to zero,
* using the allocator set at compile-time. Typically just calloc().
*
* Return value: A pointer to the allocated memory.
*
* Since: 11.0.0
**/
void* hb_calloc(size_t nmemb, size_t size) { return hb_calloc_impl (nmemb, size); }
/**
* hb_realloc:
* @ptr: The pointer to the memory to reallocate.
* @size: The new size of the memory.
*
* Reallocates the memory pointed to by @ptr to @size bytes, using the
* allocator set at compile-time. Typically just realloc().
*
* Return value: A pointer to the reallocated memory.
*
* Since: 11.0.0
**/
void* hb_realloc(void *ptr, size_t size) { return hb_realloc_impl (ptr, size); }
/**
* hb_free:
* @ptr: The pointer to the memory to free.
*
* Frees the memory pointed to by @ptr, using the allocator set at
* compile-time. Typically just free().
*
* Since: 11.0.0
**/
void hb_free(void *ptr) { hb_free_impl (ptr); }
/* If there is no visibility control, then hb-static.cc will NOT
* define anything. Instead, we get it to define one set in here

View file

@ -65,7 +65,6 @@ typedef unsigned __int64 uint64_t;
#else
# include <inttypes.h>
#endif
#include <stddef.h>
#if defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
#define HB_DEPRECATED __attribute__((__deprecated__))
@ -338,7 +337,437 @@ HB_EXTERN hb_bool_t
hb_language_matches (hb_language_t language,
hb_language_t specific);
#include "hb-script-list.h"
/**
* hb_script_t:
* @HB_SCRIPT_COMMON: `Zyyy`
* @HB_SCRIPT_INHERITED: `Zinh`
* @HB_SCRIPT_UNKNOWN: `Zzzz`
* @HB_SCRIPT_ARABIC: `Arab`
* @HB_SCRIPT_ARMENIAN: `Armn`
* @HB_SCRIPT_BENGALI: `Beng`
* @HB_SCRIPT_CYRILLIC: `Cyrl`
* @HB_SCRIPT_DEVANAGARI: `Deva`
* @HB_SCRIPT_GEORGIAN: `Geor`
* @HB_SCRIPT_GREEK: `Grek`
* @HB_SCRIPT_GUJARATI: `Gujr`
* @HB_SCRIPT_GURMUKHI: `Guru`
* @HB_SCRIPT_HANGUL: `Hang`
* @HB_SCRIPT_HAN: `Hani`
* @HB_SCRIPT_HEBREW: `Hebr`
* @HB_SCRIPT_HIRAGANA: `Hira`
* @HB_SCRIPT_KANNADA: `Knda`
* @HB_SCRIPT_KATAKANA: `Kana`
* @HB_SCRIPT_LAO: `Laoo`
* @HB_SCRIPT_LATIN: `Latn`
* @HB_SCRIPT_MALAYALAM: `Mlym`
* @HB_SCRIPT_ORIYA: `Orya`
* @HB_SCRIPT_TAMIL: `Taml`
* @HB_SCRIPT_TELUGU: `Telu`
* @HB_SCRIPT_THAI: `Thai`
* @HB_SCRIPT_TIBETAN: `Tibt`
* @HB_SCRIPT_BOPOMOFO: `Bopo`
* @HB_SCRIPT_BRAILLE: `Brai`
* @HB_SCRIPT_CANADIAN_SYLLABICS: `Cans`
* @HB_SCRIPT_CHEROKEE: `Cher`
* @HB_SCRIPT_ETHIOPIC: `Ethi`
* @HB_SCRIPT_KHMER: `Khmr`
* @HB_SCRIPT_MONGOLIAN: `Mong`
* @HB_SCRIPT_MYANMAR: `Mymr`
* @HB_SCRIPT_OGHAM: `Ogam`
* @HB_SCRIPT_RUNIC: `Runr`
* @HB_SCRIPT_SINHALA: `Sinh`
* @HB_SCRIPT_SYRIAC: `Syrc`
* @HB_SCRIPT_THAANA: `Thaa`
* @HB_SCRIPT_YI: `Yiii`
* @HB_SCRIPT_DESERET: `Dsrt`
* @HB_SCRIPT_GOTHIC: `Goth`
* @HB_SCRIPT_OLD_ITALIC: `Ital`
* @HB_SCRIPT_BUHID: `Buhd`
* @HB_SCRIPT_HANUNOO: `Hano`
* @HB_SCRIPT_TAGALOG: `Tglg`
* @HB_SCRIPT_TAGBANWA: `Tagb`
* @HB_SCRIPT_CYPRIOT: `Cprt`
* @HB_SCRIPT_LIMBU: `Limb`
* @HB_SCRIPT_LINEAR_B: `Linb`
* @HB_SCRIPT_OSMANYA: `Osma`
* @HB_SCRIPT_SHAVIAN: `Shaw`
* @HB_SCRIPT_TAI_LE: `Tale`
* @HB_SCRIPT_UGARITIC: `Ugar`
* @HB_SCRIPT_BUGINESE: `Bugi`
* @HB_SCRIPT_COPTIC: `Copt`
* @HB_SCRIPT_GLAGOLITIC: `Glag`
* @HB_SCRIPT_KHAROSHTHI: `Khar`
* @HB_SCRIPT_NEW_TAI_LUE: `Talu`
* @HB_SCRIPT_OLD_PERSIAN: `Xpeo`
* @HB_SCRIPT_SYLOTI_NAGRI: `Sylo`
* @HB_SCRIPT_TIFINAGH: `Tfng`
* @HB_SCRIPT_BALINESE: `Bali`
* @HB_SCRIPT_CUNEIFORM: `Xsux`
* @HB_SCRIPT_NKO: `Nkoo`
* @HB_SCRIPT_PHAGS_PA: `Phag`
* @HB_SCRIPT_PHOENICIAN: `Phnx`
* @HB_SCRIPT_CARIAN: `Cari`
* @HB_SCRIPT_CHAM: `Cham`
* @HB_SCRIPT_KAYAH_LI: `Kali`
* @HB_SCRIPT_LEPCHA: `Lepc`
* @HB_SCRIPT_LYCIAN: `Lyci`
* @HB_SCRIPT_LYDIAN: `Lydi`
* @HB_SCRIPT_OL_CHIKI: `Olck`
* @HB_SCRIPT_REJANG: `Rjng`
* @HB_SCRIPT_SAURASHTRA: `Saur`
* @HB_SCRIPT_SUNDANESE: `Sund`
* @HB_SCRIPT_VAI: `Vaii`
* @HB_SCRIPT_AVESTAN: `Avst`
* @HB_SCRIPT_BAMUM: `Bamu`
* @HB_SCRIPT_EGYPTIAN_HIEROGLYPHS: `Egyp`
* @HB_SCRIPT_IMPERIAL_ARAMAIC: `Armi`
* @HB_SCRIPT_INSCRIPTIONAL_PAHLAVI: `Phli`
* @HB_SCRIPT_INSCRIPTIONAL_PARTHIAN: `Prti`
* @HB_SCRIPT_JAVANESE: `Java`
* @HB_SCRIPT_KAITHI: `Kthi`
* @HB_SCRIPT_LISU: `Lisu`
* @HB_SCRIPT_MEETEI_MAYEK: `Mtei`
* @HB_SCRIPT_OLD_SOUTH_ARABIAN: `Sarb`
* @HB_SCRIPT_OLD_TURKIC: `Orkh`
* @HB_SCRIPT_SAMARITAN: `Samr`
* @HB_SCRIPT_TAI_THAM: `Lana`
* @HB_SCRIPT_TAI_VIET: `Tavt`
* @HB_SCRIPT_BATAK: `Batk`
* @HB_SCRIPT_BRAHMI: `Brah`
* @HB_SCRIPT_MANDAIC: `Mand`
* @HB_SCRIPT_CHAKMA: `Cakm`
* @HB_SCRIPT_MEROITIC_CURSIVE: `Merc`
* @HB_SCRIPT_MEROITIC_HIEROGLYPHS: `Mero`
* @HB_SCRIPT_MIAO: `Plrd`
* @HB_SCRIPT_SHARADA: `Shrd`
* @HB_SCRIPT_SORA_SOMPENG: `Sora`
* @HB_SCRIPT_TAKRI: `Takr`
* @HB_SCRIPT_BASSA_VAH: `Bass`, Since: 0.9.30
* @HB_SCRIPT_CAUCASIAN_ALBANIAN: `Aghb`, Since: 0.9.30
* @HB_SCRIPT_DUPLOYAN: `Dupl`, Since: 0.9.30
* @HB_SCRIPT_ELBASAN: `Elba`, Since: 0.9.30
* @HB_SCRIPT_GRANTHA: `Gran`, Since: 0.9.30
* @HB_SCRIPT_KHOJKI: `Khoj`, Since: 0.9.30
* @HB_SCRIPT_KHUDAWADI: `Sind`, Since: 0.9.30
* @HB_SCRIPT_LINEAR_A: `Lina`, Since: 0.9.30
* @HB_SCRIPT_MAHAJANI: `Mahj`, Since: 0.9.30
* @HB_SCRIPT_MANICHAEAN: `Mani`, Since: 0.9.30
* @HB_SCRIPT_MENDE_KIKAKUI: `Mend`, Since: 0.9.30
* @HB_SCRIPT_MODI: `Modi`, Since: 0.9.30
* @HB_SCRIPT_MRO: `Mroo`, Since: 0.9.30
* @HB_SCRIPT_NABATAEAN: `Nbat`, Since: 0.9.30
* @HB_SCRIPT_OLD_NORTH_ARABIAN: `Narb`, Since: 0.9.30
* @HB_SCRIPT_OLD_PERMIC: `Perm`, Since: 0.9.30
* @HB_SCRIPT_PAHAWH_HMONG: `Hmng`, Since: 0.9.30
* @HB_SCRIPT_PALMYRENE: `Palm`, Since: 0.9.30
* @HB_SCRIPT_PAU_CIN_HAU: `Pauc`, Since: 0.9.30
* @HB_SCRIPT_PSALTER_PAHLAVI: `Phlp`, Since: 0.9.30
* @HB_SCRIPT_SIDDHAM: `Sidd`, Since: 0.9.30
* @HB_SCRIPT_TIRHUTA: `Tirh`, Since: 0.9.30
* @HB_SCRIPT_WARANG_CITI: `Wara`, Since: 0.9.30
* @HB_SCRIPT_AHOM: `Ahom`, Since: 0.9.30
* @HB_SCRIPT_ANATOLIAN_HIEROGLYPHS: `Hluw`, Since: 0.9.30
* @HB_SCRIPT_HATRAN: `Hatr`, Since: 0.9.30
* @HB_SCRIPT_MULTANI: `Mult`, Since: 0.9.30
* @HB_SCRIPT_OLD_HUNGARIAN: `Hung`, Since: 0.9.30
* @HB_SCRIPT_SIGNWRITING: `Sgnw`, Since: 0.9.30
* @HB_SCRIPT_ADLAM: `Adlm`, Since: 1.3.0
* @HB_SCRIPT_BHAIKSUKI: `Bhks`, Since: 1.3.0
* @HB_SCRIPT_MARCHEN: `Marc`, Since: 1.3.0
* @HB_SCRIPT_OSAGE: `Osge`, Since: 1.3.0
* @HB_SCRIPT_TANGUT: `Tang`, Since: 1.3.0
* @HB_SCRIPT_NEWA: `Newa`, Since: 1.3.0
* @HB_SCRIPT_MASARAM_GONDI: `Gonm`, Since: 1.6.0
* @HB_SCRIPT_NUSHU: `Nshu`, Since: 1.6.0
* @HB_SCRIPT_SOYOMBO: `Soyo`, Since: 1.6.0
* @HB_SCRIPT_ZANABAZAR_SQUARE: `Zanb`, Since: 1.6.0
* @HB_SCRIPT_DOGRA: `Dogr`, Since: 1.8.0
* @HB_SCRIPT_GUNJALA_GONDI: `Gong`, Since: 1.8.0
* @HB_SCRIPT_HANIFI_ROHINGYA: `Rohg`, Since: 1.8.0
* @HB_SCRIPT_MAKASAR: `Maka`, Since: 1.8.0
* @HB_SCRIPT_MEDEFAIDRIN: `Medf`, Since: 1.8.0
* @HB_SCRIPT_OLD_SOGDIAN: `Sogo`, Since: 1.8.0
* @HB_SCRIPT_SOGDIAN: `Sogd`, Since: 1.8.0
* @HB_SCRIPT_ELYMAIC: `Elym`, Since: 2.4.0
* @HB_SCRIPT_NANDINAGARI: `Nand`, Since: 2.4.0
* @HB_SCRIPT_NYIAKENG_PUACHUE_HMONG: `Hmnp`, Since: 2.4.0
* @HB_SCRIPT_WANCHO: `Wcho`, Since: 2.4.0
* @HB_SCRIPT_CHORASMIAN: `Chrs`, Since: 2.6.7
* @HB_SCRIPT_DIVES_AKURU: `Diak`, Since: 2.6.7
* @HB_SCRIPT_KHITAN_SMALL_SCRIPT: `Kits`, Since: 2.6.7
* @HB_SCRIPT_YEZIDI: `Yezi`, Since: 2.6.7
* @HB_SCRIPT_CYPRO_MINOAN: `Cpmn`, Since: 3.0.0
* @HB_SCRIPT_OLD_UYGHUR: `Ougr`, Since: 3.0.0
* @HB_SCRIPT_TANGSA: `Tnsa`, Since: 3.0.0
* @HB_SCRIPT_TOTO: `Toto`, Since: 3.0.0
* @HB_SCRIPT_VITHKUQI: `Vith`, Since: 3.0.0
* @HB_SCRIPT_MATH: `Zmth`, Since: 3.4.0
* @HB_SCRIPT_KAWI: `Kawi`, Since: 5.2.0
* @HB_SCRIPT_NAG_MUNDARI: `Nagm`, Since: 5.2.0
* @HB_SCRIPT_GARAY: `Gara`, Since: 10.0.0
* @HB_SCRIPT_GURUNG_KHEMA: `Gukh`, Since: 10.0.0
* @HB_SCRIPT_KIRAT_RAI: `Krai`, Since: 10.0.0
* @HB_SCRIPT_OL_ONAL: `Onao`, Since: 10.0.0
* @HB_SCRIPT_SUNUWAR: `Sunu`, Since: 10.0.0
* @HB_SCRIPT_TODHRI: `Todr`, Since: 10.0.0
* @HB_SCRIPT_TULU_TIGALARI: `Tutg`, Since: 10.0.0
* @HB_SCRIPT_INVALID: No script set
*
* Data type for scripts. Each #hb_script_t's value is an #hb_tag_t corresponding
* to the four-letter values defined by [ISO 15924](https://unicode.org/iso15924/).
*
* See also the Script (sc) property of the Unicode Character Database.
*
**/
/* https://docs.google.com/spreadsheets/d/1Y90M0Ie3MUJ6UVCRDOypOtijlMDLNNyyLk36T6iMu0o */
typedef enum
{
HB_SCRIPT_COMMON = HB_TAG ('Z','y','y','y'), /*1.1*/
HB_SCRIPT_INHERITED = HB_TAG ('Z','i','n','h'), /*1.1*/
HB_SCRIPT_UNKNOWN = HB_TAG ('Z','z','z','z'), /*5.0*/
HB_SCRIPT_ARABIC = HB_TAG ('A','r','a','b'), /*1.1*/
HB_SCRIPT_ARMENIAN = HB_TAG ('A','r','m','n'), /*1.1*/
HB_SCRIPT_BENGALI = HB_TAG ('B','e','n','g'), /*1.1*/
HB_SCRIPT_CYRILLIC = HB_TAG ('C','y','r','l'), /*1.1*/
HB_SCRIPT_DEVANAGARI = HB_TAG ('D','e','v','a'), /*1.1*/
HB_SCRIPT_GEORGIAN = HB_TAG ('G','e','o','r'), /*1.1*/
HB_SCRIPT_GREEK = HB_TAG ('G','r','e','k'), /*1.1*/
HB_SCRIPT_GUJARATI = HB_TAG ('G','u','j','r'), /*1.1*/
HB_SCRIPT_GURMUKHI = HB_TAG ('G','u','r','u'), /*1.1*/
HB_SCRIPT_HANGUL = HB_TAG ('H','a','n','g'), /*1.1*/
HB_SCRIPT_HAN = HB_TAG ('H','a','n','i'), /*1.1*/
HB_SCRIPT_HEBREW = HB_TAG ('H','e','b','r'), /*1.1*/
HB_SCRIPT_HIRAGANA = HB_TAG ('H','i','r','a'), /*1.1*/
HB_SCRIPT_KANNADA = HB_TAG ('K','n','d','a'), /*1.1*/
HB_SCRIPT_KATAKANA = HB_TAG ('K','a','n','a'), /*1.1*/
HB_SCRIPT_LAO = HB_TAG ('L','a','o','o'), /*1.1*/
HB_SCRIPT_LATIN = HB_TAG ('L','a','t','n'), /*1.1*/
HB_SCRIPT_MALAYALAM = HB_TAG ('M','l','y','m'), /*1.1*/
HB_SCRIPT_ORIYA = HB_TAG ('O','r','y','a'), /*1.1*/
HB_SCRIPT_TAMIL = HB_TAG ('T','a','m','l'), /*1.1*/
HB_SCRIPT_TELUGU = HB_TAG ('T','e','l','u'), /*1.1*/
HB_SCRIPT_THAI = HB_TAG ('T','h','a','i'), /*1.1*/
HB_SCRIPT_TIBETAN = HB_TAG ('T','i','b','t'), /*2.0*/
HB_SCRIPT_BOPOMOFO = HB_TAG ('B','o','p','o'), /*3.0*/
HB_SCRIPT_BRAILLE = HB_TAG ('B','r','a','i'), /*3.0*/
HB_SCRIPT_CANADIAN_SYLLABICS = HB_TAG ('C','a','n','s'), /*3.0*/
HB_SCRIPT_CHEROKEE = HB_TAG ('C','h','e','r'), /*3.0*/
HB_SCRIPT_ETHIOPIC = HB_TAG ('E','t','h','i'), /*3.0*/
HB_SCRIPT_KHMER = HB_TAG ('K','h','m','r'), /*3.0*/
HB_SCRIPT_MONGOLIAN = HB_TAG ('M','o','n','g'), /*3.0*/
HB_SCRIPT_MYANMAR = HB_TAG ('M','y','m','r'), /*3.0*/
HB_SCRIPT_OGHAM = HB_TAG ('O','g','a','m'), /*3.0*/
HB_SCRIPT_RUNIC = HB_TAG ('R','u','n','r'), /*3.0*/
HB_SCRIPT_SINHALA = HB_TAG ('S','i','n','h'), /*3.0*/
HB_SCRIPT_SYRIAC = HB_TAG ('S','y','r','c'), /*3.0*/
HB_SCRIPT_THAANA = HB_TAG ('T','h','a','a'), /*3.0*/
HB_SCRIPT_YI = HB_TAG ('Y','i','i','i'), /*3.0*/
HB_SCRIPT_DESERET = HB_TAG ('D','s','r','t'), /*3.1*/
HB_SCRIPT_GOTHIC = HB_TAG ('G','o','t','h'), /*3.1*/
HB_SCRIPT_OLD_ITALIC = HB_TAG ('I','t','a','l'), /*3.1*/
HB_SCRIPT_BUHID = HB_TAG ('B','u','h','d'), /*3.2*/
HB_SCRIPT_HANUNOO = HB_TAG ('H','a','n','o'), /*3.2*/
HB_SCRIPT_TAGALOG = HB_TAG ('T','g','l','g'), /*3.2*/
HB_SCRIPT_TAGBANWA = HB_TAG ('T','a','g','b'), /*3.2*/
HB_SCRIPT_CYPRIOT = HB_TAG ('C','p','r','t'), /*4.0*/
HB_SCRIPT_LIMBU = HB_TAG ('L','i','m','b'), /*4.0*/
HB_SCRIPT_LINEAR_B = HB_TAG ('L','i','n','b'), /*4.0*/
HB_SCRIPT_OSMANYA = HB_TAG ('O','s','m','a'), /*4.0*/
HB_SCRIPT_SHAVIAN = HB_TAG ('S','h','a','w'), /*4.0*/
HB_SCRIPT_TAI_LE = HB_TAG ('T','a','l','e'), /*4.0*/
HB_SCRIPT_UGARITIC = HB_TAG ('U','g','a','r'), /*4.0*/
HB_SCRIPT_BUGINESE = HB_TAG ('B','u','g','i'), /*4.1*/
HB_SCRIPT_COPTIC = HB_TAG ('C','o','p','t'), /*4.1*/
HB_SCRIPT_GLAGOLITIC = HB_TAG ('G','l','a','g'), /*4.1*/
HB_SCRIPT_KHAROSHTHI = HB_TAG ('K','h','a','r'), /*4.1*/
HB_SCRIPT_NEW_TAI_LUE = HB_TAG ('T','a','l','u'), /*4.1*/
HB_SCRIPT_OLD_PERSIAN = HB_TAG ('X','p','e','o'), /*4.1*/
HB_SCRIPT_SYLOTI_NAGRI = HB_TAG ('S','y','l','o'), /*4.1*/
HB_SCRIPT_TIFINAGH = HB_TAG ('T','f','n','g'), /*4.1*/
HB_SCRIPT_BALINESE = HB_TAG ('B','a','l','i'), /*5.0*/
HB_SCRIPT_CUNEIFORM = HB_TAG ('X','s','u','x'), /*5.0*/
HB_SCRIPT_NKO = HB_TAG ('N','k','o','o'), /*5.0*/
HB_SCRIPT_PHAGS_PA = HB_TAG ('P','h','a','g'), /*5.0*/
HB_SCRIPT_PHOENICIAN = HB_TAG ('P','h','n','x'), /*5.0*/
HB_SCRIPT_CARIAN = HB_TAG ('C','a','r','i'), /*5.1*/
HB_SCRIPT_CHAM = HB_TAG ('C','h','a','m'), /*5.1*/
HB_SCRIPT_KAYAH_LI = HB_TAG ('K','a','l','i'), /*5.1*/
HB_SCRIPT_LEPCHA = HB_TAG ('L','e','p','c'), /*5.1*/
HB_SCRIPT_LYCIAN = HB_TAG ('L','y','c','i'), /*5.1*/
HB_SCRIPT_LYDIAN = HB_TAG ('L','y','d','i'), /*5.1*/
HB_SCRIPT_OL_CHIKI = HB_TAG ('O','l','c','k'), /*5.1*/
HB_SCRIPT_REJANG = HB_TAG ('R','j','n','g'), /*5.1*/
HB_SCRIPT_SAURASHTRA = HB_TAG ('S','a','u','r'), /*5.1*/
HB_SCRIPT_SUNDANESE = HB_TAG ('S','u','n','d'), /*5.1*/
HB_SCRIPT_VAI = HB_TAG ('V','a','i','i'), /*5.1*/
HB_SCRIPT_AVESTAN = HB_TAG ('A','v','s','t'), /*5.2*/
HB_SCRIPT_BAMUM = HB_TAG ('B','a','m','u'), /*5.2*/
HB_SCRIPT_EGYPTIAN_HIEROGLYPHS = HB_TAG ('E','g','y','p'), /*5.2*/
HB_SCRIPT_IMPERIAL_ARAMAIC = HB_TAG ('A','r','m','i'), /*5.2*/
HB_SCRIPT_INSCRIPTIONAL_PAHLAVI = HB_TAG ('P','h','l','i'), /*5.2*/
HB_SCRIPT_INSCRIPTIONAL_PARTHIAN = HB_TAG ('P','r','t','i'), /*5.2*/
HB_SCRIPT_JAVANESE = HB_TAG ('J','a','v','a'), /*5.2*/
HB_SCRIPT_KAITHI = HB_TAG ('K','t','h','i'), /*5.2*/
HB_SCRIPT_LISU = HB_TAG ('L','i','s','u'), /*5.2*/
HB_SCRIPT_MEETEI_MAYEK = HB_TAG ('M','t','e','i'), /*5.2*/
HB_SCRIPT_OLD_SOUTH_ARABIAN = HB_TAG ('S','a','r','b'), /*5.2*/
HB_SCRIPT_OLD_TURKIC = HB_TAG ('O','r','k','h'), /*5.2*/
HB_SCRIPT_SAMARITAN = HB_TAG ('S','a','m','r'), /*5.2*/
HB_SCRIPT_TAI_THAM = HB_TAG ('L','a','n','a'), /*5.2*/
HB_SCRIPT_TAI_VIET = HB_TAG ('T','a','v','t'), /*5.2*/
HB_SCRIPT_BATAK = HB_TAG ('B','a','t','k'), /*6.0*/
HB_SCRIPT_BRAHMI = HB_TAG ('B','r','a','h'), /*6.0*/
HB_SCRIPT_MANDAIC = HB_TAG ('M','a','n','d'), /*6.0*/
HB_SCRIPT_CHAKMA = HB_TAG ('C','a','k','m'), /*6.1*/
HB_SCRIPT_MEROITIC_CURSIVE = HB_TAG ('M','e','r','c'), /*6.1*/
HB_SCRIPT_MEROITIC_HIEROGLYPHS = HB_TAG ('M','e','r','o'), /*6.1*/
HB_SCRIPT_MIAO = HB_TAG ('P','l','r','d'), /*6.1*/
HB_SCRIPT_SHARADA = HB_TAG ('S','h','r','d'), /*6.1*/
HB_SCRIPT_SORA_SOMPENG = HB_TAG ('S','o','r','a'), /*6.1*/
HB_SCRIPT_TAKRI = HB_TAG ('T','a','k','r'), /*6.1*/
/*
* Since: 0.9.30
*/
HB_SCRIPT_BASSA_VAH = HB_TAG ('B','a','s','s'), /*7.0*/
HB_SCRIPT_CAUCASIAN_ALBANIAN = HB_TAG ('A','g','h','b'), /*7.0*/
HB_SCRIPT_DUPLOYAN = HB_TAG ('D','u','p','l'), /*7.0*/
HB_SCRIPT_ELBASAN = HB_TAG ('E','l','b','a'), /*7.0*/
HB_SCRIPT_GRANTHA = HB_TAG ('G','r','a','n'), /*7.0*/
HB_SCRIPT_KHOJKI = HB_TAG ('K','h','o','j'), /*7.0*/
HB_SCRIPT_KHUDAWADI = HB_TAG ('S','i','n','d'), /*7.0*/
HB_SCRIPT_LINEAR_A = HB_TAG ('L','i','n','a'), /*7.0*/
HB_SCRIPT_MAHAJANI = HB_TAG ('M','a','h','j'), /*7.0*/
HB_SCRIPT_MANICHAEAN = HB_TAG ('M','a','n','i'), /*7.0*/
HB_SCRIPT_MENDE_KIKAKUI = HB_TAG ('M','e','n','d'), /*7.0*/
HB_SCRIPT_MODI = HB_TAG ('M','o','d','i'), /*7.0*/
HB_SCRIPT_MRO = HB_TAG ('M','r','o','o'), /*7.0*/
HB_SCRIPT_NABATAEAN = HB_TAG ('N','b','a','t'), /*7.0*/
HB_SCRIPT_OLD_NORTH_ARABIAN = HB_TAG ('N','a','r','b'), /*7.0*/
HB_SCRIPT_OLD_PERMIC = HB_TAG ('P','e','r','m'), /*7.0*/
HB_SCRIPT_PAHAWH_HMONG = HB_TAG ('H','m','n','g'), /*7.0*/
HB_SCRIPT_PALMYRENE = HB_TAG ('P','a','l','m'), /*7.0*/
HB_SCRIPT_PAU_CIN_HAU = HB_TAG ('P','a','u','c'), /*7.0*/
HB_SCRIPT_PSALTER_PAHLAVI = HB_TAG ('P','h','l','p'), /*7.0*/
HB_SCRIPT_SIDDHAM = HB_TAG ('S','i','d','d'), /*7.0*/
HB_SCRIPT_TIRHUTA = HB_TAG ('T','i','r','h'), /*7.0*/
HB_SCRIPT_WARANG_CITI = HB_TAG ('W','a','r','a'), /*7.0*/
HB_SCRIPT_AHOM = HB_TAG ('A','h','o','m'), /*8.0*/
HB_SCRIPT_ANATOLIAN_HIEROGLYPHS = HB_TAG ('H','l','u','w'), /*8.0*/
HB_SCRIPT_HATRAN = HB_TAG ('H','a','t','r'), /*8.0*/
HB_SCRIPT_MULTANI = HB_TAG ('M','u','l','t'), /*8.0*/
HB_SCRIPT_OLD_HUNGARIAN = HB_TAG ('H','u','n','g'), /*8.0*/
HB_SCRIPT_SIGNWRITING = HB_TAG ('S','g','n','w'), /*8.0*/
/*
* Since 1.3.0
*/
HB_SCRIPT_ADLAM = HB_TAG ('A','d','l','m'), /*9.0*/
HB_SCRIPT_BHAIKSUKI = HB_TAG ('B','h','k','s'), /*9.0*/
HB_SCRIPT_MARCHEN = HB_TAG ('M','a','r','c'), /*9.0*/
HB_SCRIPT_OSAGE = HB_TAG ('O','s','g','e'), /*9.0*/
HB_SCRIPT_TANGUT = HB_TAG ('T','a','n','g'), /*9.0*/
HB_SCRIPT_NEWA = HB_TAG ('N','e','w','a'), /*9.0*/
/*
* Since 1.6.0
*/
HB_SCRIPT_MASARAM_GONDI = HB_TAG ('G','o','n','m'), /*10.0*/
HB_SCRIPT_NUSHU = HB_TAG ('N','s','h','u'), /*10.0*/
HB_SCRIPT_SOYOMBO = HB_TAG ('S','o','y','o'), /*10.0*/
HB_SCRIPT_ZANABAZAR_SQUARE = HB_TAG ('Z','a','n','b'), /*10.0*/
/*
* Since 1.8.0
*/
HB_SCRIPT_DOGRA = HB_TAG ('D','o','g','r'), /*11.0*/
HB_SCRIPT_GUNJALA_GONDI = HB_TAG ('G','o','n','g'), /*11.0*/
HB_SCRIPT_HANIFI_ROHINGYA = HB_TAG ('R','o','h','g'), /*11.0*/
HB_SCRIPT_MAKASAR = HB_TAG ('M','a','k','a'), /*11.0*/
HB_SCRIPT_MEDEFAIDRIN = HB_TAG ('M','e','d','f'), /*11.0*/
HB_SCRIPT_OLD_SOGDIAN = HB_TAG ('S','o','g','o'), /*11.0*/
HB_SCRIPT_SOGDIAN = HB_TAG ('S','o','g','d'), /*11.0*/
/*
* Since 2.4.0
*/
HB_SCRIPT_ELYMAIC = HB_TAG ('E','l','y','m'), /*12.0*/
HB_SCRIPT_NANDINAGARI = HB_TAG ('N','a','n','d'), /*12.0*/
HB_SCRIPT_NYIAKENG_PUACHUE_HMONG = HB_TAG ('H','m','n','p'), /*12.0*/
HB_SCRIPT_WANCHO = HB_TAG ('W','c','h','o'), /*12.0*/
/*
* Since 2.6.7
*/
HB_SCRIPT_CHORASMIAN = HB_TAG ('C','h','r','s'), /*13.0*/
HB_SCRIPT_DIVES_AKURU = HB_TAG ('D','i','a','k'), /*13.0*/
HB_SCRIPT_KHITAN_SMALL_SCRIPT = HB_TAG ('K','i','t','s'), /*13.0*/
HB_SCRIPT_YEZIDI = HB_TAG ('Y','e','z','i'), /*13.0*/
/*
* Since 3.0.0
*/
HB_SCRIPT_CYPRO_MINOAN = HB_TAG ('C','p','m','n'), /*14.0*/
HB_SCRIPT_OLD_UYGHUR = HB_TAG ('O','u','g','r'), /*14.0*/
HB_SCRIPT_TANGSA = HB_TAG ('T','n','s','a'), /*14.0*/
HB_SCRIPT_TOTO = HB_TAG ('T','o','t','o'), /*14.0*/
HB_SCRIPT_VITHKUQI = HB_TAG ('V','i','t','h'), /*14.0*/
/*
* Since 3.4.0
*/
HB_SCRIPT_MATH = HB_TAG ('Z','m','t','h'),
/*
* Since 5.2.0
*/
HB_SCRIPT_KAWI = HB_TAG ('K','a','w','i'), /*15.0*/
HB_SCRIPT_NAG_MUNDARI = HB_TAG ('N','a','g','m'), /*15.0*/
/*
* Since 10.0.0
*/
HB_SCRIPT_GARAY = HB_TAG ('G','a','r','a'), /*16.0*/
HB_SCRIPT_GURUNG_KHEMA = HB_TAG ('G','u','k','h'), /*16.0*/
HB_SCRIPT_KIRAT_RAI = HB_TAG ('K','r','a','i'), /*16.0*/
HB_SCRIPT_OL_ONAL = HB_TAG ('O','n','a','o'), /*16.0*/
HB_SCRIPT_SUNUWAR = HB_TAG ('S','u','n','u'), /*16.0*/
HB_SCRIPT_TODHRI = HB_TAG ('T','o','d','r'), /*16.0*/
HB_SCRIPT_TULU_TIGALARI = HB_TAG ('T','u','t','g'), /*16.0*/
/* No script set. */
HB_SCRIPT_INVALID = HB_TAG_NONE,
/*< private >*/
/* Dummy values to ensure any hb_tag_t value can be passed/stored as hb_script_t
* without risking undefined behavior. We have two, for historical reasons.
* HB_TAG_MAX used to be unsigned, but that was invalid Ansi C, so was changed
* to _HB_SCRIPT_MAX_VALUE to be equal to HB_TAG_MAX_SIGNED as well.
*
* See this thread for technicalities:
*
* https://lists.freedesktop.org/archives/harfbuzz/2014-March/004150.html
*/
_HB_SCRIPT_MAX_VALUE = HB_TAG_MAX_SIGNED, /*< skip >*/
_HB_SCRIPT_MAX_VALUE_SIGNED = HB_TAG_MAX_SIGNED /*< skip >*/
} hb_script_t;
/* Script functions */
@ -519,16 +948,6 @@ typedef struct hb_glyph_extents_t {
*/
typedef struct hb_font_t hb_font_t;
/* Not of much use to clients. */
HB_EXTERN void*
hb_malloc (size_t size);
HB_EXTERN void*
hb_calloc (size_t nmemb, size_t size);
HB_EXTERN void*
hb_realloc (void *ptr, size_t size);
HB_EXTERN void
hb_free (void *ptr);
HB_END_DECLS
#endif /* HB_COMMON_H */

View file

@ -146,7 +146,6 @@
#ifdef HB_NO_DRAW
#define HB_NO_OUTLINE
#define HB_NO_PAINT
#endif
#ifdef HB_NO_GETENV
@ -192,6 +191,7 @@
#ifdef HB_MINIMIZE_MEMORY_USAGE
#define HB_NO_GDEF_CACHE
#define HB_NO_OT_LAYOUT_LOOKUP_CACHE
#define HB_NO_OT_FONT_ADVANCE_CACHE
#define HB_NO_OT_FONT_CMAP_CACHE
#endif

View file

@ -28,8 +28,7 @@
#ifdef HAVE_CORETEXT
#include "hb-coretext.hh"
#include "hb-aat-layout-trak-table.hh"
#include "hb-coretext.h"
#include "hb-draw.hh"
#include "hb-font.hh"
@ -43,17 +42,24 @@
# define kCTFontOrientationVertical kCTFontVerticalOrientation
#endif
#define MAX_GLYPHS 256u
#define MAX_GLYPHS 64u
static void
_hb_coretext_font_destroy (void *font_data)
{
CTFontRef ct_font = (CTFontRef) font_data;
CFRelease (ct_font);
}
static hb_bool_t
hb_coretext_get_nominal_glyph (hb_font_t *font,
void *font_data HB_UNUSED,
hb_coretext_get_nominal_glyph (hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t unicode,
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
CTFontRef ct_font = (CTFontRef) font_data;
UniChar ch[2];
CGGlyph cg_glyph[2];
unsigned count = 0;
@ -79,7 +85,7 @@ hb_coretext_get_nominal_glyph (hb_font_t *font,
}
static unsigned int
hb_coretext_get_nominal_glyphs (hb_font_t *font,
hb_coretext_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
void *font_data,
unsigned int count,
const hb_codepoint_t *first_unicode,
@ -88,8 +94,6 @@ hb_coretext_get_nominal_glyphs (hb_font_t *font,
unsigned int glyph_stride,
void *user_data HB_UNUSED)
{
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
// If any non-BMP codepoint is requested, use the slow path.
bool slow_path = false;
auto *unicode = first_unicode;
@ -115,6 +119,8 @@ hb_coretext_get_nominal_glyphs (hb_font_t *font,
return count;
}
CTFontRef ct_font = (CTFontRef) font_data;
UniChar ch[MAX_GLYPHS];
CGGlyph cg_glyph[MAX_GLYPHS];
for (unsigned i = 0; i < count; i += MAX_GLYPHS)
@ -146,14 +152,14 @@ hb_coretext_get_nominal_glyphs (hb_font_t *font,
}
static hb_bool_t
hb_coretext_get_variation_glyph (hb_font_t *font,
void *font_data HB_UNUSED,
hb_coretext_get_variation_glyph (hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t unicode,
hb_codepoint_t variation_selector,
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
CTFontRef ct_font = (CTFontRef) font_data;
UniChar ch[4];
CGGlyph cg_glyph[4];
@ -188,17 +194,12 @@ hb_coretext_get_variation_glyph (hb_font_t *font,
if (cg_glyph[i])
return false;
// Humm. CoreText falls back to the default glyph if the variation selector
// is not supported. We cannot truly detect that case. So, in essence,
// we are always returning true here...
*glyph = cg_glyph[0];
return true;
}
static void
hb_coretext_get_glyph_h_advances (hb_font_t* font,
void* font_data HB_UNUSED,
hb_coretext_get_glyph_h_advances (hb_font_t* font, void* font_data,
unsigned count,
const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
@ -206,11 +207,10 @@ hb_coretext_get_glyph_h_advances (hb_font_t* font,
unsigned advance_stride,
void *user_data HB_UNUSED)
{
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
CTFontRef ct_font = (CTFontRef) font_data;
CGFloat ct_font_size = CTFontGetSize (ct_font);
CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
hb_position_t tracking = font->face->table.trak->get_tracking (font, HB_DIRECTION_LTR, 0.f);
CGGlyph cg_glyph[MAX_GLYPHS];
CGSize advances[MAX_GLYPHS];
@ -225,7 +225,7 @@ hb_coretext_get_glyph_h_advances (hb_font_t* font,
CTFontGetAdvancesForGlyphs (ct_font, kCTFontOrientationHorizontal, cg_glyph, advances, c);
for (unsigned j = 0; j < c; j++)
{
*first_advance = round (advances[j].width * x_mult) - tracking;
*first_advance = round (advances[j].width * x_mult);
first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
}
}
@ -233,8 +233,7 @@ hb_coretext_get_glyph_h_advances (hb_font_t* font,
#ifndef HB_NO_VERTICAL
static void
hb_coretext_get_glyph_v_advances (hb_font_t* font,
void* font_data HB_UNUSED,
hb_coretext_get_glyph_v_advances (hb_font_t* font, void* font_data,
unsigned count,
const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
@ -242,11 +241,10 @@ hb_coretext_get_glyph_v_advances (hb_font_t* font,
unsigned advance_stride,
void *user_data HB_UNUSED)
{
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
CTFontRef ct_font = (CTFontRef) font_data;
CGFloat ct_font_size = CTFontGetSize (ct_font);
CGFloat y_mult = (CGFloat) -font->y_scale / ct_font_size;
hb_position_t tracking = font->face->table.trak->get_tracking (font, HB_DIRECTION_TTB, 0.f);
CGGlyph cg_glyph[MAX_GLYPHS];
CGSize advances[MAX_GLYPHS];
@ -261,21 +259,23 @@ hb_coretext_get_glyph_v_advances (hb_font_t* font,
CTFontGetAdvancesForGlyphs (ct_font, kCTFontOrientationVertical, cg_glyph, advances, c);
for (unsigned j = 0; j < c; j++)
{
*first_advance = round (advances[j].width * y_mult) - tracking;
*first_advance = round (advances[j].width * y_mult);
first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
}
}
}
#endif
#ifndef HB_NO_VERTICAL
static hb_bool_t
hb_coretext_get_glyph_v_origin (hb_font_t *font,
void *font_data HB_UNUSED,
void *font_data,
hb_codepoint_t glyph,
hb_position_t *x,
hb_position_t *y,
void *user_data HB_UNUSED)
{
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
CTFontRef ct_font = (CTFontRef) font_data;
CGFloat ct_font_size = CTFontGetSize (ct_font);
CGFloat x_mult = (CGFloat) -font->x_scale / ct_font_size;
@ -294,12 +294,12 @@ hb_coretext_get_glyph_v_origin (hb_font_t *font,
static hb_bool_t
hb_coretext_get_glyph_extents (hb_font_t *font,
void *font_data HB_UNUSED,
void *font_data,
hb_codepoint_t glyph,
hb_glyph_extents_t *extents,
void *user_data HB_UNUSED)
{
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
CTFontRef ct_font = (CTFontRef) font_data;
CGFloat ct_font_size = CTFontGetSize (ct_font);
CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
@ -310,21 +310,20 @@ hb_coretext_get_glyph_extents (hb_font_t *font,
kCTFontOrientationDefault, glyphs, NULL, 1);
extents->x_bearing = round (bounds.origin.x * x_mult);
extents->y_bearing = round ((bounds.origin.y + bounds.size.height) * y_mult);
extents->y_bearing = round (bounds.origin.y * y_mult);
extents->width = round (bounds.size.width * x_mult);
extents->height = round (bounds.origin.y * y_mult) - extents->y_bearing;
extents->height = round (bounds.size.height * y_mult);
return true;
}
static hb_bool_t
hb_coretext_get_font_h_extents (hb_font_t *font,
void *font_data HB_UNUSED,
void *font_data,
hb_font_extents_t *metrics,
void *user_data HB_UNUSED)
{
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
CTFontRef ct_font = (CTFontRef) font_data;
CGFloat ct_font_size = CTFontGetSize (ct_font);
CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size;
@ -372,7 +371,7 @@ hb_coretext_draw_glyph (hb_font_t *font,
hb_draw_funcs_t *draw_funcs, void *draw_data,
void *user_data)
{
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
CTFontRef ct_font = (CTFontRef) font_data;
CGFloat ct_font_size = CTFontGetSize (ct_font);
CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
@ -416,20 +415,17 @@ hb_coretext_get_glyph_name (hb_font_t *font,
(UInt8 *) name, size, &len);
name[len] = '\0';
CFRelease (cf_name);
return true;
}
static hb_bool_t
hb_coretext_get_glyph_from_name (hb_font_t *font,
void *font_data HB_UNUSED,
hb_coretext_get_glyph_from_name (hb_font_t *font HB_UNUSED,
void *font_data,
const char *name, int len,
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
CTFontRef ct_font = (CTFontRef) font_data;
if (len == -1)
len = strlen (name);
@ -462,8 +458,10 @@ static struct hb_coretext_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t
hb_font_funcs_set_font_h_extents_func (funcs, hb_coretext_get_font_h_extents, nullptr, nullptr);
hb_font_funcs_set_glyph_h_advances_func (funcs, hb_coretext_get_glyph_h_advances, nullptr, nullptr);
//hb_font_funcs_set_glyph_h_origin_func (funcs, hb_coretext_get_glyph_h_origin, nullptr, nullptr);
#ifndef HB_NO_VERTICAL
//hb_font_funcs_set_font_v_extents_func (funcs, hb_coretext_get_font_v_extents, nullptr, nullptr);
hb_font_funcs_set_glyph_v_advances_func (funcs, hb_coretext_get_glyph_v_advances, nullptr, nullptr);
hb_font_funcs_set_glyph_v_origin_func (funcs, hb_coretext_get_glyph_v_origin, nullptr, nullptr);
#endif
@ -532,7 +530,8 @@ hb_coretext_font_set_funcs (hb_font_t *font)
hb_font_set_funcs (font,
_hb_coretext_get_font_funcs (),
nullptr, nullptr);
(void *) CFRetain (ct_font),
_hb_coretext_font_destroy);
}
#undef MAX_GLYPHS

View file

@ -32,9 +32,279 @@
#include "hb-shaper-impl.hh"
#include "hb-coretext.hh"
#include "hb-coretext.h"
#include "hb-aat-layout.hh"
/**
* SECTION:hb-coretext
* @title: hb-coretext
* @short_description: CoreText integration
* @include: hb-coretext.h
*
* Functions for using HarfBuzz with the CoreText fonts.
**/
static CTFontRef create_ct_font (CGFontRef cg_font, CGFloat font_size);
static void
release_table_data (void *user_data)
{
CFDataRef cf_data = reinterpret_cast<CFDataRef> (user_data);
CFRelease(cf_data);
}
static hb_blob_t *
_hb_cg_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
{
CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
if (unlikely (!cf_data))
return nullptr;
const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data));
const size_t length = CFDataGetLength (cf_data);
if (!data || !length)
{
CFRelease (cf_data);
return nullptr;
}
return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY,
reinterpret_cast<void *> (const_cast<__CFData *> (cf_data)),
release_table_data);
}
static unsigned
_hb_cg_get_table_tags (const hb_face_t *face HB_UNUSED,
unsigned int start_offset,
unsigned int *table_count,
hb_tag_t *table_tags,
void *user_data)
{
CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
CTFontRef ct_font = create_ct_font (cg_font, (CGFloat) HB_CORETEXT_DEFAULT_FONT_SIZE);
auto arr = CTFontCopyAvailableTables (ct_font, kCTFontTableOptionNoOptions);
unsigned population = (unsigned) CFArrayGetCount (arr);
unsigned end_offset;
if (!table_count)
goto done;
if (unlikely (start_offset >= population))
{
*table_count = 0;
goto done;
}
end_offset = start_offset + *table_count;
if (unlikely (end_offset < start_offset))
{
*table_count = 0;
goto done;
}
end_offset= hb_min (end_offset, (unsigned) population);
*table_count = end_offset - start_offset;
for (unsigned i = start_offset; i < end_offset; i++)
{
CTFontTableTag tag = (CTFontTableTag)(uintptr_t) CFArrayGetValueAtIndex (arr, i);
table_tags[i - start_offset] = tag;
}
done:
CFRelease (arr);
CFRelease (ct_font);
return population;
}
static void
_hb_cg_font_release (void *data)
{
CGFontRelease ((CGFontRef) data);
}
static CTFontDescriptorRef
get_last_resort_font_desc ()
{
// TODO Handle allocation failures?
CTFontDescriptorRef last_resort = CTFontDescriptorCreateWithNameAndSize (CFSTR("LastResort"), 0);
CFArrayRef cascade_list = CFArrayCreate (kCFAllocatorDefault,
(const void **) &last_resort,
1,
&kCFTypeArrayCallBacks);
CFRelease (last_resort);
CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
(const void **) &kCTFontCascadeListAttribute,
(const void **) &cascade_list,
1,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFRelease (cascade_list);
CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
CFRelease (attributes);
return font_desc;
}
static void
release_data (void *info, const void *data, size_t size)
{
assert (hb_blob_get_length ((hb_blob_t *) info) == size &&
hb_blob_get_data ((hb_blob_t *) info, nullptr) == data);
hb_blob_destroy ((hb_blob_t *) info);
}
static CGFontRef
create_cg_font (hb_face_t *face)
{
CGFontRef cg_font = nullptr;
if (face->destroy == _hb_cg_font_release)
{
cg_font = CGFontRetain ((CGFontRef) face->user_data);
}
else
{
hb_blob_t *blob = hb_face_reference_blob (face);
unsigned int blob_length;
const char *blob_data = hb_blob_get_data (blob, &blob_length);
if (unlikely (!blob_length))
DEBUG_MSG (CORETEXT, face, "Face has empty blob");
CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
if (likely (provider))
{
cg_font = CGFontCreateWithDataProvider (provider);
if (unlikely (!cg_font))
DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
CGDataProviderRelease (provider);
}
}
return cg_font;
}
static CTFontRef
create_ct_font (CGFontRef cg_font, CGFloat font_size)
{
CTFontRef ct_font = nullptr;
/* CoreText does not enable trak table usage / tracking when creating a CTFont
* using CTFontCreateWithGraphicsFont. The only way of enabling tracking seems
* to be through the CTFontCreateUIFontForLanguage call. */
CFStringRef cg_postscript_name = CGFontCopyPostScriptName (cg_font);
if (CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSText")) ||
CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSDisplay")))
{
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1080
# define kCTFontUIFontSystem kCTFontSystemFontType
# define kCTFontUIFontEmphasizedSystem kCTFontEmphasizedSystemFontType
#endif
CTFontUIFontType font_type = kCTFontUIFontSystem;
if (CFStringHasSuffix (cg_postscript_name, CFSTR ("-Bold")))
font_type = kCTFontUIFontEmphasizedSystem;
ct_font = CTFontCreateUIFontForLanguage (font_type, font_size, nullptr);
CFStringRef ct_result_name = CTFontCopyPostScriptName(ct_font);
if (CFStringCompare (ct_result_name, cg_postscript_name, 0) != kCFCompareEqualTo)
{
CFRelease(ct_font);
ct_font = nullptr;
}
CFRelease (ct_result_name);
}
CFRelease (cg_postscript_name);
if (!ct_font)
ct_font = CTFontCreateWithGraphicsFont (cg_font, font_size, nullptr, nullptr);
if (unlikely (!ct_font)) {
DEBUG_MSG (CORETEXT, cg_font, "Font CTFontCreateWithGraphicsFont() failed");
return nullptr;
}
/* crbug.com/576941 and crbug.com/625902 and the investigation in the latter
* bug indicate that the cascade list reconfiguration occasionally causes
* crashes in CoreText on OS X 10.9, thus let's skip this step on older
* operating system versions. Except for the emoji font, where _not_
* reconfiguring the cascade list causes CoreText crashes. For details, see
* crbug.com/549610 */
// 0x00070000 stands for "kCTVersionNumber10_10", see CoreText.h
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
if (&CTGetCoreTextVersion != nullptr && CTGetCoreTextVersion() < 0x00070000) {
#pragma GCC diagnostic pop
CFStringRef fontName = CTFontCopyPostScriptName (ct_font);
bool isEmojiFont = CFStringCompare (fontName, CFSTR("AppleColorEmoji"), 0) == kCFCompareEqualTo;
CFRelease (fontName);
if (!isEmojiFont)
return ct_font;
}
CFURLRef original_url = nullptr;
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
ATSFontRef atsFont;
FSRef fsref;
OSStatus status;
atsFont = CTFontGetPlatformFont (ct_font, NULL);
status = ATSFontGetFileReference (atsFont, &fsref);
if (status == noErr)
original_url = CFURLCreateFromFSRef (NULL, &fsref);
#else
original_url = (CFURLRef) CTFontCopyAttribute (ct_font, kCTFontURLAttribute);
#endif
/* Create font copy with cascade list that has LastResort first; this speeds up CoreText
* font fallback which we don't need anyway. */
{
CTFontDescriptorRef last_resort_font_desc = get_last_resort_font_desc ();
CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0.0, nullptr, last_resort_font_desc);
CFRelease (last_resort_font_desc);
if (new_ct_font)
{
/* The CTFontCreateCopyWithAttributes call fails to stay on the same font
* when reconfiguring the cascade list and may switch to a different font
* when there are fonts that go by the same name, since the descriptor is
* just name and size.
*
* Avoid reconfiguring the cascade lists if the new font is outside the
* system locations that we cannot access from the sandboxed renderer
* process in Blink. This can be detected by the new file URL location
* that the newly found font points to. */
CFURLRef new_url = nullptr;
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
atsFont = CTFontGetPlatformFont (new_ct_font, NULL);
status = ATSFontGetFileReference (atsFont, &fsref);
if (status == noErr)
new_url = CFURLCreateFromFSRef (NULL, &fsref);
#else
new_url = (CFURLRef) CTFontCopyAttribute (new_ct_font, kCTFontURLAttribute);
#endif
// Keep reconfigured font if URL cannot be retrieved (seems to be the case
// on Mac OS 10.12 Sierra), speculative fix for crbug.com/625606
if (!original_url || !new_url || CFEqual (original_url, new_url)) {
CFRelease (ct_font);
ct_font = new_ct_font;
} else {
CFRelease (new_ct_font);
DEBUG_MSG (CORETEXT, ct_font, "Discarding reconfigured CTFont, location changed.");
}
if (new_url)
CFRelease (new_url);
}
else
DEBUG_MSG (CORETEXT, ct_font, "Font copy with empty cascade list failed");
}
if (original_url)
CFRelease (original_url);
return ct_font;
}
hb_coretext_face_data_t *
_hb_coretext_shaper_face_data_create (hb_face_t *face)
{
@ -55,6 +325,102 @@ _hb_coretext_shaper_face_data_destroy (hb_coretext_face_data_t *data)
CFRelease ((CGFontRef) data);
}
/**
* hb_coretext_face_create:
* @cg_font: The CGFontRef to work upon
*
* Creates an #hb_face_t face object from the specified
* CGFontRef.
*
* Return value: (transfer full): The new face object
*
* Since: 0.9.10
*/
hb_face_t *
hb_coretext_face_create (CGFontRef cg_font)
{
hb_face_t *face = hb_face_create_for_tables (_hb_cg_reference_table, CGFontRetain (cg_font), _hb_cg_font_release);
hb_face_set_get_table_tags_func (face, _hb_cg_get_table_tags, cg_font, nullptr);
return face;
}
/**
* hb_coretext_face_create_from_file_or_fail:
* @file_name: A font filename
* @index: The index of the face within the file
*
* Creates an #hb_face_t face object from the specified
* font file and face index.
*
* This is similar in functionality to hb_face_create_from_file_or_fail(),
* but uses the CoreText library for loading the font file.
*
* Return value: (transfer full): The new face object, or `NULL` if
* no face is found at the specified index or the file cannot be read.
*
* Since: 10.1.0
*/
hb_face_t *
hb_coretext_face_create_from_file_or_fail (const char *file_name,
unsigned int index)
{
auto url = CFURLCreateFromFileSystemRepresentation (nullptr,
(const UInt8 *) file_name,
strlen (file_name),
false);
if (unlikely (!url))
return nullptr;
auto ct_font_desc_array = CTFontManagerCreateFontDescriptorsFromURL (url);
if (unlikely (!ct_font_desc_array))
{
CFRelease (url);
return nullptr;
}
auto ct_font_desc = (CFArrayGetCount (ct_font_desc_array) > index) ?
(CTFontDescriptorRef) CFArrayGetValueAtIndex (ct_font_desc_array, index) : nullptr;
if (unlikely (!ct_font_desc))
{
CFRelease (ct_font_desc_array);
CFRelease (url);
return nullptr;
}
CFRelease (url);
auto ct_font = ct_font_desc ? CTFontCreateWithFontDescriptor (ct_font_desc, 0, nullptr) : nullptr;
CFRelease (ct_font_desc_array);
if (unlikely (!ct_font))
return nullptr;
auto cg_font = ct_font ? CTFontCopyGraphicsFont (ct_font, nullptr) : nullptr;
CFRelease (ct_font);
if (unlikely (!cg_font))
return nullptr;
hb_face_t *face = hb_coretext_face_create (cg_font);
CFRelease (cg_font);
if (unlikely (hb_face_is_immutable (face)))
return nullptr;
return face;
}
/**
* hb_coretext_face_get_cg_font:
* @face: The #hb_face_t to work upon
*
* Fetches the CGFontRef associated with an #hb_face_t
* face object
*
* Return value: the CGFontRef found
*
* Since: 0.9.10
*/
CGFontRef
hb_coretext_face_get_cg_font (hb_face_t *face)
{
return (CGFontRef) (const void *) face->data.coretext;
}
hb_coretext_font_data_t *
_hb_coretext_shaper_font_data_create (hb_font_t *font)
@ -73,9 +439,7 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font)
return nullptr;
}
unsigned num_axes = hb_ot_var_get_axis_count (face);
// https://github.com/harfbuzz/harfbuzz/issues/5163
if (num_axes)
if (font->num_coords)
{
CFMutableDictionaryRef variations =
CFDictionaryCreateMutable (kCFAllocatorDefault,
@ -83,15 +447,14 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font)
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
unsigned count = hb_max (num_axes, font->num_coords);
for (unsigned i = 0; i < count; i++)
for (unsigned i = 0; i < font->num_coords; i++)
{
hb_ot_var_axis_info_t info;
unsigned int c = 1;
hb_ot_var_get_axis_infos (font->face, i, &c, &info);
float v = i < font->num_coords ?
hb_clamp (font->design_coords[i], info.min_value, info.max_value) :
info.default_value;
if (font->design_coords[i] == info.default_value)
continue;
float v = hb_clamp (font->design_coords[i], info.min_value, info.max_value);
CFNumberRef tag_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &info.tag);
CFNumberRef value_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberFloatType, &v);
@ -126,6 +489,94 @@ _hb_coretext_shaper_font_data_destroy (hb_coretext_font_data_t *data)
CFRelease ((CTFontRef) data);
}
/**
* hb_coretext_font_create:
* @ct_font: The CTFontRef to work upon
*
* Creates an #hb_font_t font object from the specified
* CTFontRef.
*
* The created font uses the default font functions implemented
* natively by HarfBuzz. If you want to use the CoreText font functions
* instead (rarely needed), you can do so by calling
* by hb_coretext_font_set_funcs().
*
* Return value: (transfer full): The new font object
*
* Since: 1.7.2
**/
hb_font_t *
hb_coretext_font_create (CTFontRef ct_font)
{
CGFontRef cg_font = CTFontCopyGraphicsFont (ct_font, nullptr);
hb_face_t *face = hb_coretext_face_create (cg_font);
CFRelease (cg_font);
hb_font_t *font = hb_font_create (face);
hb_face_destroy (face);
if (unlikely (hb_object_is_immutable (font)))
return font;
hb_font_set_ptem (font, CTFontGetSize (ct_font));
/* Copy font variations */
CFDictionaryRef variations = CTFontCopyVariation (ct_font);
if (variations)
{
hb_vector_t<hb_variation_t> vars;
hb_vector_t<CFTypeRef> keys;
hb_vector_t<CFTypeRef> values;
CFIndex count = CFDictionaryGetCount (variations);
if (unlikely (!vars.alloc_exact (count) || !keys.resize_exact (count) || !values.resize_exact (count)))
goto done;
// Fetch them one by one and collect in a vector of our own.
CFDictionaryGetKeysAndValues (variations, keys.arrayZ, values.arrayZ);
for (CFIndex i = 0; i < count; i++)
{
int tag;
float value;
CFNumberGetValue ((CFNumberRef) keys.arrayZ[i], kCFNumberIntType, &tag);
CFNumberGetValue ((CFNumberRef) values.arrayZ[i], kCFNumberFloatType, &value);
hb_variation_t var = {tag, value};
vars.push (var);
}
hb_font_set_variations (font, vars.arrayZ, vars.length);
done:
CFRelease (variations);
}
/* Let there be dragons here... */
font->data.coretext.cmpexch (nullptr, (hb_coretext_font_data_t *) CFRetain (ct_font));
// https://github.com/harfbuzz/harfbuzz/pull/4895#issuecomment-2408471254
//hb_coretext_font_set_funcs (font);
return font;
}
/**
* hb_coretext_font_get_ct_font:
* @font: #hb_font_t to work upon
*
* Fetches the CTFontRef associated with the specified
* #hb_font_t font object.
*
* Return value: the CTFontRef found
*
* Since: 0.9.10
*/
CTFontRef
hb_coretext_font_get_ct_font (hb_font_t *font)
{
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
return ct_font ? (CTFontRef) ct_font : nullptr;
}
/*
* shaper
*/
@ -195,7 +646,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
* B1 M1 B2 M2, and B1-B2 form a ligature, M2's cluster will
* continue pointing to B2 even though B2 was merged into B1's
* cluster... */
if (HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES (buffer->cluster_level))
if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
{
hb_unicode_funcs_t *unicode = buffer->unicode;
unsigned int count = buffer->len;
@ -559,7 +1010,7 @@ resize_and_retry:
CFArrayRef glyph_runs = CTLineGetGlyphRuns (line);
unsigned int num_runs = CFArrayGetCount (glyph_runs);
DEBUG_MSG (CORETEXT, nullptr, "Num runs: %u", num_runs);
DEBUG_MSG (CORETEXT, nullptr, "Num runs: %d", num_runs);
buffer->len = 0;
uint32_t status_or = 0;
@ -841,7 +1292,7 @@ resize_and_retry:
* or the native OT backend, only that the cluster indices will be
* monotonic in the output buffer. */
if (count > 1 && (status_or & kCTRunStatusNonMonotonic) &&
HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (buffer->cluster_level))
buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
{
hb_glyph_info_t *info = buffer->info;
if (HB_DIRECTION_IS_FORWARD (buffer->props.direction))

View file

@ -1,572 +0,0 @@
/*
* Copyright © 2012,2013 Mozilla Foundation.
* Copyright © 2012,2013 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.
*
* Mozilla Author(s): Jonathan Kew
* Google Author(s): Behdad Esfahbod
*/
#include "hb.hh"
#ifdef HAVE_CORETEXT
#include "hb-shaper-impl.hh"
#include "hb-coretext.hh"
/**
* SECTION:hb-coretext
* @title: hb-coretext
* @short_description: CoreText integration
* @include: hb-coretext.h
*
* Functions for using HarfBuzz with the CoreText fonts.
**/
static void
release_table_data (void *user_data)
{
CFDataRef cf_data = reinterpret_cast<CFDataRef> (user_data);
CFRelease(cf_data);
}
static hb_blob_t *
_hb_cg_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
{
CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
if (unlikely (!cf_data))
return nullptr;
const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data));
const size_t length = CFDataGetLength (cf_data);
if (!data || !length)
{
CFRelease (cf_data);
return nullptr;
}
return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY,
reinterpret_cast<void *> (const_cast<__CFData *> (cf_data)),
release_table_data);
}
static unsigned
_hb_cg_get_table_tags (const hb_face_t *face HB_UNUSED,
unsigned int start_offset,
unsigned int *table_count,
hb_tag_t *table_tags,
void *user_data)
{
CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
CTFontRef ct_font = create_ct_font (cg_font, (CGFloat) HB_CORETEXT_DEFAULT_FONT_SIZE);
auto arr = CTFontCopyAvailableTables (ct_font, kCTFontTableOptionNoOptions);
unsigned population = (unsigned) CFArrayGetCount (arr);
unsigned end_offset;
if (!table_count)
goto done;
if (unlikely (start_offset >= population))
{
*table_count = 0;
goto done;
}
end_offset = start_offset + *table_count;
if (unlikely (end_offset < start_offset))
{
*table_count = 0;
goto done;
}
end_offset= hb_min (end_offset, (unsigned) population);
*table_count = end_offset - start_offset;
for (unsigned i = start_offset; i < end_offset; i++)
{
CTFontTableTag tag = (CTFontTableTag)(uintptr_t) CFArrayGetValueAtIndex (arr, i);
table_tags[i - start_offset] = tag;
}
done:
CFRelease (arr);
CFRelease (ct_font);
return population;
}
static void
_hb_cg_font_release (void *data)
{
CGFontRelease ((CGFontRef) data);
}
static CTFontDescriptorRef
get_last_resort_font_desc ()
{
// TODO Handle allocation failures?
CTFontDescriptorRef last_resort = CTFontDescriptorCreateWithNameAndSize (CFSTR("LastResort"), 0);
CFArrayRef cascade_list = CFArrayCreate (kCFAllocatorDefault,
(const void **) &last_resort,
1,
&kCFTypeArrayCallBacks);
CFRelease (last_resort);
CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
(const void **) &kCTFontCascadeListAttribute,
(const void **) &cascade_list,
1,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFRelease (cascade_list);
CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
CFRelease (attributes);
return font_desc;
}
static void
release_data (void *info, const void *data, size_t size)
{
assert (hb_blob_get_length ((hb_blob_t *) info) == size &&
hb_blob_get_data ((hb_blob_t *) info, nullptr) == data);
hb_blob_destroy ((hb_blob_t *) info);
}
CGFontRef
create_cg_font (CFArrayRef ct_font_desc_array, unsigned int named_instance_index)
{
if (named_instance_index == 0)
{
// Default instance. We don't know which one is it. Return the first one.
// We will set the correct variations on it later.
}
else
named_instance_index--;
auto ct_font_desc = (CFArrayGetCount (ct_font_desc_array) > named_instance_index) ?
(CTFontDescriptorRef) CFArrayGetValueAtIndex (ct_font_desc_array, named_instance_index) : nullptr;
if (unlikely (!ct_font_desc))
{
CFRelease (ct_font_desc_array);
return nullptr;
}
auto ct_font = ct_font_desc ? CTFontCreateWithFontDescriptor (ct_font_desc, 0, nullptr) : nullptr;
CFRelease (ct_font_desc_array);
if (unlikely (!ct_font))
return nullptr;
auto cg_font = ct_font ? CTFontCopyGraphicsFont (ct_font, nullptr) : nullptr;
CFRelease (ct_font);
return cg_font;
}
CGFontRef
create_cg_font (hb_blob_t *blob, unsigned int index)
{
hb_blob_make_immutable (blob);
unsigned int blob_length;
const char *blob_data = hb_blob_get_data (blob, &blob_length);
if (unlikely (!blob_length))
DEBUG_MSG (CORETEXT, blob, "Empty blob");
unsigned ttc_index = index & 0xFFFF;
unsigned named_instance_index = index >> 16;
if (ttc_index != 0)
{
DEBUG_MSG (CORETEXT, blob, "TTC index %u not supported", ttc_index);
return nullptr; // CoreText does not support TTCs
}
if (unlikely (named_instance_index != 0))
{
auto ct_font_desc_array = CTFontManagerCreateFontDescriptorsFromData (CFDataCreate (kCFAllocatorDefault, (const UInt8 *) blob_data, blob_length));
if (unlikely (!ct_font_desc_array))
return nullptr;
return create_cg_font (ct_font_desc_array, named_instance_index);
}
hb_blob_reference (blob);
CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
CGFontRef cg_font = nullptr;
if (likely (provider))
{
cg_font = CGFontCreateWithDataProvider (provider);
if (unlikely (!cg_font))
DEBUG_MSG (CORETEXT, blob, "CGFontCreateWithDataProvider() failed");
CGDataProviderRelease (provider);
}
return cg_font;
}
CGFontRef
create_cg_font (hb_face_t *face)
{
CGFontRef cg_font = nullptr;
if (face->destroy == _hb_cg_font_release)
cg_font = CGFontRetain ((CGFontRef) face->user_data);
else
{
hb_blob_t *blob = hb_face_reference_blob (face);
cg_font = create_cg_font (blob, face->index);
hb_blob_destroy (blob);
}
return cg_font;
}
CTFontRef
create_ct_font (CGFontRef cg_font, CGFloat font_size)
{
CTFontRef ct_font = nullptr;
/* CoreText does not enable trak table usage / tracking when creating a CTFont
* using CTFontCreateWithGraphicsFont. The only way of enabling tracking seems
* to be through the CTFontCreateUIFontForLanguage call. */
CFStringRef cg_postscript_name = CGFontCopyPostScriptName (cg_font);
if (CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSText")) ||
CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSDisplay")))
{
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1080
# define kCTFontUIFontSystem kCTFontSystemFontType
# define kCTFontUIFontEmphasizedSystem kCTFontEmphasizedSystemFontType
#endif
CTFontUIFontType font_type = kCTFontUIFontSystem;
if (CFStringHasSuffix (cg_postscript_name, CFSTR ("-Bold")))
font_type = kCTFontUIFontEmphasizedSystem;
ct_font = CTFontCreateUIFontForLanguage (font_type, font_size, nullptr);
CFStringRef ct_result_name = CTFontCopyPostScriptName(ct_font);
if (CFStringCompare (ct_result_name, cg_postscript_name, 0) != kCFCompareEqualTo)
{
CFRelease(ct_font);
ct_font = nullptr;
}
CFRelease (ct_result_name);
}
CFRelease (cg_postscript_name);
if (!ct_font)
ct_font = CTFontCreateWithGraphicsFont (cg_font, font_size, nullptr, nullptr);
if (unlikely (!ct_font)) {
DEBUG_MSG (CORETEXT, cg_font, "Font CTFontCreateWithGraphicsFont() failed");
return nullptr;
}
/* crbug.com/576941 and crbug.com/625902 and the investigation in the latter
* bug indicate that the cascade list reconfiguration occasionally causes
* crashes in CoreText on OS X 10.9, thus let's skip this step on older
* operating system versions. Except for the emoji font, where _not_
* reconfiguring the cascade list causes CoreText crashes. For details, see
* crbug.com/549610 */
// 0x00070000 stands for "kCTVersionNumber10_10", see CoreText.h
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
if (&CTGetCoreTextVersion != nullptr && CTGetCoreTextVersion() < 0x00070000) {
#pragma GCC diagnostic pop
CFStringRef fontName = CTFontCopyPostScriptName (ct_font);
bool isEmojiFont = CFStringCompare (fontName, CFSTR("AppleColorEmoji"), 0) == kCFCompareEqualTo;
CFRelease (fontName);
if (!isEmojiFont)
return ct_font;
}
CFURLRef original_url = nullptr;
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
ATSFontRef atsFont;
FSRef fsref;
OSStatus status;
atsFont = CTFontGetPlatformFont (ct_font, NULL);
status = ATSFontGetFileReference (atsFont, &fsref);
if (status == noErr)
original_url = CFURLCreateFromFSRef (NULL, &fsref);
#else
original_url = (CFURLRef) CTFontCopyAttribute (ct_font, kCTFontURLAttribute);
#endif
/* Create font copy with cascade list that has LastResort first; this speeds up CoreText
* font fallback which we don't need anyway. */
{
CTFontDescriptorRef last_resort_font_desc = get_last_resort_font_desc ();
CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0.0, nullptr, last_resort_font_desc);
CFRelease (last_resort_font_desc);
if (new_ct_font)
{
/* The CTFontCreateCopyWithAttributes call fails to stay on the same font
* when reconfiguring the cascade list and may switch to a different font
* when there are fonts that go by the same name, since the descriptor is
* just name and size.
*
* Avoid reconfiguring the cascade lists if the new font is outside the
* system locations that we cannot access from the sandboxed renderer
* process in Blink. This can be detected by the new file URL location
* that the newly found font points to. */
CFURLRef new_url = nullptr;
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
atsFont = CTFontGetPlatformFont (new_ct_font, NULL);
status = ATSFontGetFileReference (atsFont, &fsref);
if (status == noErr)
new_url = CFURLCreateFromFSRef (NULL, &fsref);
#else
new_url = (CFURLRef) CTFontCopyAttribute (new_ct_font, kCTFontURLAttribute);
#endif
// Keep reconfigured font if URL cannot be retrieved (seems to be the case
// on Mac OS 10.12 Sierra), speculative fix for crbug.com/625606
if (!original_url || !new_url || CFEqual (original_url, new_url)) {
CFRelease (ct_font);
ct_font = new_ct_font;
} else {
CFRelease (new_ct_font);
DEBUG_MSG (CORETEXT, ct_font, "Discarding reconfigured CTFont, location changed.");
}
if (new_url)
CFRelease (new_url);
}
else
DEBUG_MSG (CORETEXT, ct_font, "Font copy with empty cascade list failed");
}
if (original_url)
CFRelease (original_url);
return ct_font;
}
/**
* hb_coretext_face_create:
* @cg_font: The CGFontRef to work upon
*
* Creates an #hb_face_t face object from the specified
* CGFontRef.
*
* Return value: (transfer full): The new face object
*
* Since: 0.9.10
*/
hb_face_t *
hb_coretext_face_create (CGFontRef cg_font)
{
hb_face_t *face = hb_face_create_for_tables (_hb_cg_reference_table, CGFontRetain (cg_font), _hb_cg_font_release);
hb_face_set_get_table_tags_func (face, _hb_cg_get_table_tags, cg_font, nullptr);
return face;
}
/**
* hb_coretext_face_create_from_file_or_fail:
* @file_name: A font filename
* @index: The index of the face within the file
*
* Creates an #hb_face_t face object from the specified
* font file and face index.
*
* This is similar in functionality to hb_face_create_from_file_or_fail(),
* but uses the CoreText library for loading the font file.
*
* Return value: (transfer full): The new face object, or `NULL` if
* no face is found at the specified index or the file cannot be read.
*
* Since: 10.1.0
*/
hb_face_t *
hb_coretext_face_create_from_file_or_fail (const char *file_name,
unsigned int index)
{
auto url = CFURLCreateFromFileSystemRepresentation (nullptr,
(const UInt8 *) file_name,
strlen (file_name),
false);
if (unlikely (!url))
return nullptr;
auto ct_font_desc_array = CTFontManagerCreateFontDescriptorsFromURL (url);
if (unlikely (!ct_font_desc_array))
{
CFRelease (url);
return nullptr;
}
unsigned ttc_index = index & 0xFFFF;
unsigned named_instance_index = index >> 16;
if (ttc_index != 0)
{
DEBUG_MSG (CORETEXT, nullptr, "TTC index %u not supported", ttc_index);
return nullptr; // CoreText does not support TTCs
}
auto cg_font = create_cg_font (ct_font_desc_array, named_instance_index);
CFRelease (url);
hb_face_t *face = hb_coretext_face_create (cg_font);
CFRelease (cg_font);
if (unlikely (hb_face_is_immutable (face)))
return nullptr;
hb_face_set_index (face, index);
return face;
}
/**
* hb_coretext_face_create_from_blob_or_fail:
* @blob: A blob containing the font data
* @index: The index of the face within the blob
*
* Creates an #hb_face_t face object from the specified
* blob and face index.
*
* This is similar in functionality to hb_face_create_from_blob_or_fail(),
* but uses the CoreText library for loading the font data.
*
* Return value: (transfer full): The new face object, or `NULL` if
* no face is found at the specified index or the blob cannot be read.
*
* Since: 11.0.0
*/
hb_face_t *
hb_coretext_face_create_from_blob_or_fail (hb_blob_t *blob,
unsigned int index)
{
auto cg_font = create_cg_font (blob, index);
if (unlikely (!cg_font))
return nullptr;
hb_face_t *face = hb_coretext_face_create (cg_font);
CFRelease (cg_font);
if (unlikely (hb_face_is_immutable (face)))
return nullptr;
hb_face_set_index (face, index);
return face;
}
/**
* hb_coretext_face_get_cg_font:
* @face: The #hb_face_t to work upon
*
* Fetches the CGFontRef associated with an #hb_face_t
* face object
*
* Return value: the CGFontRef found
*
* Since: 0.9.10
*/
CGFontRef
hb_coretext_face_get_cg_font (hb_face_t *face)
{
return (CGFontRef) (const void *) face->data.coretext;
}
/**
* hb_coretext_font_create:
* @ct_font: The CTFontRef to work upon
*
* Creates an #hb_font_t font object from the specified
* CTFontRef.
*
* The created font uses the default font functions implemented
* natively by HarfBuzz. If you want to use the CoreText font functions
* instead (rarely needed), you can do so by calling
* by hb_coretext_font_set_funcs().
*
* Return value: (transfer full): The new font object
*
* Since: 1.7.2
**/
hb_font_t *
hb_coretext_font_create (CTFontRef ct_font)
{
CGFontRef cg_font = CTFontCopyGraphicsFont (ct_font, nullptr);
hb_face_t *face = hb_coretext_face_create (cg_font);
CFRelease (cg_font);
hb_font_t *font = hb_font_create (face);
hb_face_destroy (face);
if (unlikely (hb_object_is_immutable (font)))
return font;
hb_font_set_ptem (font, CTFontGetSize (ct_font));
/* Copy font variations */
CFDictionaryRef variations = CTFontCopyVariation (ct_font);
if (variations)
{
hb_vector_t<hb_variation_t> vars;
hb_vector_t<CFTypeRef> keys;
hb_vector_t<CFTypeRef> values;
CFIndex count = CFDictionaryGetCount (variations);
if (unlikely (!vars.alloc_exact (count) || !keys.resize_exact (count) || !values.resize_exact (count)))
goto done;
// Fetch them one by one and collect in a vector of our own.
CFDictionaryGetKeysAndValues (variations, keys.arrayZ, values.arrayZ);
for (CFIndex i = 0; i < count; i++)
{
int tag;
float value;
CFNumberGetValue ((CFNumberRef) keys.arrayZ[i], kCFNumberIntType, &tag);
CFNumberGetValue ((CFNumberRef) values.arrayZ[i], kCFNumberFloatType, &value);
hb_variation_t var = {tag, value};
vars.push (var);
}
hb_font_set_variations (font, vars.arrayZ, vars.length);
done:
CFRelease (variations);
}
/* Let there be dragons here... */
font->data.coretext.cmpexch (nullptr, (hb_coretext_font_data_t *) CFRetain (ct_font));
// https://github.com/harfbuzz/harfbuzz/pull/4895#issuecomment-2408471254
//hb_coretext_font_set_funcs (font);
return font;
}
/**
* hb_coretext_font_get_ct_font:
* @font: #hb_font_t to work upon
*
* Fetches the CTFontRef associated with the specified
* #hb_font_t font object.
*
* Return value: the CTFontRef found
*
* Since: 0.9.10
*/
CTFontRef
hb_coretext_font_get_ct_font (hb_font_t *font)
{
return (CTFontRef) (const void *) font->data.coretext;
}
#endif

View file

@ -84,10 +84,6 @@ HB_EXTERN hb_face_t *
hb_coretext_face_create_from_file_or_fail (const char *file_name,
unsigned int index);
HB_EXTERN hb_face_t *
hb_coretext_face_create_from_blob_or_fail (hb_blob_t *blob,
unsigned int index);
HB_EXTERN hb_font_t *
hb_coretext_font_create (CTFontRef ct_font);

View file

@ -1,53 +0,0 @@
/*
* Copyright © 2012,2013 Mozilla Foundation.
* Copyright © 2012,2013 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.
*
* Mozilla Author(s): Jonathan Kew
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_CORETEXT_HH
#define HB_CORETEXT_HH
#include "hb.hh"
#include "hb-coretext.h"
#include "hb-aat-layout.hh"
HB_INTERNAL CGFontRef
create_cg_font (CFArrayRef ct_font_desc_array, unsigned int index);
HB_INTERNAL CGFontRef
create_cg_font (hb_blob_t *blob, unsigned int index);
HB_INTERNAL CGFontRef
create_cg_font (hb_face_t *face);
HB_INTERNAL CTFontRef
create_ct_font (CGFontRef cg_font, CGFloat font_size);
#endif /* HB_CORETEXT_HH */

View file

@ -49,15 +49,15 @@ struct hb_options_t
};
union hb_options_union_t {
unsigned i;
int i;
hb_options_t opts;
};
static_assert ((sizeof (hb_atomic_t<unsigned>) >= sizeof (hb_options_union_t)), "");
static_assert ((sizeof (hb_atomic_int_t) >= sizeof (hb_options_union_t)), "");
HB_INTERNAL void
_hb_options_init ();
extern HB_INTERNAL hb_atomic_t<unsigned> _hb_options;
extern HB_INTERNAL hb_atomic_int_t _hb_options;
static inline hb_options_t
hb_options ()

View file

@ -38,11 +38,11 @@
* For Floyd's tortoise and hare algorithm, see:
* https://en.wikipedia.org/wiki/Cycle_detection#Floyd's_tortoise_and_hare
*
* hb_decycler_t is O(n) in the number of nodes in the DFS traversal
* if there are no cycles. Unlike Floyd's algorithm, hb_decycler_t
* can be used in a DFS traversal, where the graph is not a simple
* linked list, but a tree with possible cycles. Like Floyd's algorithm,
* it is constant-memory (~three pointers).
* Like Floyd's algorithm, hb_decycler_t is O(n) in the number of nodes
* in the graph. Unlike Floyd's algorithm, hb_decycler_t is designed
* to be used in a DFS traversal, where the graph is not a simple
* linked list, but a tree with cycles. Like Floyd's algorithm, it is
* constant-memory (just two pointers).
*
* The decycler works by creating an implicit linked-list on the stack,
* of the path from the root to the current node, and apply Floyd's
@ -89,7 +89,7 @@ struct hb_decycler_t
friend struct hb_decycler_node_t;
private:
bool tortoise_awake = false;
bool tortoise_asleep = true;
hb_decycler_node_t *tortoise = nullptr;
hb_decycler_node_t *hare = nullptr;
};
@ -100,18 +100,15 @@ struct hb_decycler_node_t
{
u.decycler = &decycler;
decycler.tortoise_awake = !decycler.tortoise_awake;
decycler.tortoise_asleep = !decycler.tortoise_asleep;
if (!decycler.tortoise)
{
// First node.
assert (decycler.tortoise_awake);
assert (!decycler.hare);
decycler.tortoise = decycler.hare = this;
return;
}
if (decycler.tortoise_awake)
if (!decycler.tortoise_asleep)
decycler.tortoise = decycler.tortoise->u.next; // Time to move.
this->prev = decycler.hare;
@ -131,10 +128,10 @@ struct hb_decycler_node_t
prev->u.decycler = &decycler;
assert (decycler.tortoise);
if (decycler.tortoise_awake)
if (!decycler.tortoise_asleep)
decycler.tortoise = decycler.tortoise->prev;
decycler.tortoise_awake = !decycler.tortoise_awake;
decycler.tortoise_asleep = !decycler.tortoise_asleep;
}
bool visit (uintptr_t value_)

View file

@ -1,388 +0,0 @@
/*
* Copyright © 2025 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
*/
#include "hb.hh"
#ifdef HAVE_DIRECTWRITE
#include "hb-directwrite.h"
#include <d2d1.h>
#include "hb-draw.hh"
#include "hb-font.hh"
#include "hb-machinery.hh"
#define MAX_GLYPHS 256u
static unsigned int
hb_directwrite_get_nominal_glyphs (hb_font_t *font,
void *font_data HB_UNUSED,
unsigned int count,
const hb_codepoint_t *first_unicode,
unsigned int unicode_stride,
hb_codepoint_t *first_glyph,
unsigned int glyph_stride,
void *user_data HB_UNUSED)
{
IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
for (unsigned i = 0; i < count;)
{
UINT32 unicodes[MAX_GLYPHS];
UINT16 gids[MAX_GLYPHS];
unsigned n = hb_min (MAX_GLYPHS, count - i);
for (unsigned j = 0; j < n; j++)
{
unicodes[j] = *first_unicode;
first_unicode = &StructAtOffset<const hb_codepoint_t> (first_unicode, unicode_stride);
}
if (!SUCCEEDED (dw_face->GetGlyphIndices (unicodes, n, gids)))
return i;
for (unsigned j = 0; j < n; j++)
{
if (!gids[j])
return i + j;
*first_glyph = gids[j];
first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
}
i += n;
}
return count;
}
static hb_bool_t
hb_directwrite_get_font_h_extents (hb_font_t *font,
void *font_data HB_UNUSED,
hb_font_extents_t *metrics,
void *user_data HB_UNUSED)
{
IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
DWRITE_FONT_METRICS dw_metrics;
dw_face->GetMetrics (&dw_metrics);
metrics->ascender = font->em_scale_y (dw_metrics.ascent);
metrics->descender = -font->em_scale_y (dw_metrics.descent);
metrics->line_gap = font->em_scale_y (dw_metrics.lineGap);
return true;
}
static void
hb_directwrite_get_glyph_h_advances (hb_font_t* font,
void* font_data HB_UNUSED,
unsigned count,
const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride,
void *user_data HB_UNUSED)
{
IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
IDWriteFontFace1 *dw_face1 = nullptr;
dw_face->QueryInterface (__uuidof(IDWriteFontFace1), (void**)&dw_face1);
assert (dw_face1);
for (unsigned i = 0; i < count;)
{
UINT16 gids[MAX_GLYPHS];
INT32 advances[MAX_GLYPHS];
unsigned n = hb_min (MAX_GLYPHS, count - i);
for (unsigned j = 0; j < n; j++)
{
gids[j] = *first_glyph;
advances[j] = 0;
first_glyph = &StructAtOffset<const hb_codepoint_t> (first_glyph, glyph_stride);
}
dw_face1->GetDesignGlyphAdvances (n, gids, advances, false);
for (unsigned j = 0; j < n; j++)
{
*first_advance = font->em_scale_x (advances[j]);
first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
}
i += n;
}
}
#ifndef HB_NO_VERTICAL
static void
hb_directwrite_get_glyph_v_advances (hb_font_t* font,
void* font_data HB_UNUSED,
unsigned count,
const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride,
void *user_data HB_UNUSED)
{
IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
IDWriteFontFace1 *dw_face1 = nullptr;
dw_face->QueryInterface (__uuidof(IDWriteFontFace1), (void**)&dw_face1);
assert (dw_face1);
for (unsigned i = 0; i < count;)
{
UINT16 gids[MAX_GLYPHS];
INT32 advances[MAX_GLYPHS];
unsigned n = hb_min (MAX_GLYPHS, count - i);
for (unsigned j = 0; j < n; j++)
{
gids[j] = *first_glyph;
advances[j] = 0;
first_glyph = &StructAtOffset<const hb_codepoint_t> (first_glyph, glyph_stride);
}
dw_face1->GetDesignGlyphAdvances (n, gids, advances, true);
for (unsigned j = 0; j < n; j++)
{
*first_advance = -font->em_scale_y (advances[j]);
first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
}
i += n;
}
}
static hb_bool_t
hb_directwrite_get_glyph_v_origin (hb_font_t *font,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
hb_position_t *x,
hb_position_t *y,
void *user_data HB_UNUSED)
{
IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
UINT16 gid = glyph;
DWRITE_GLYPH_METRICS metrics;
if (FAILED (dw_face->GetDesignGlyphMetrics (&gid, 1, &metrics)))
return false;
*x = font->em_scale_x (metrics.advanceWidth / 2);
*y = font->em_scale_y (metrics.verticalOriginY); // Untested
return true;
}
#endif
static hb_bool_t
hb_directwrite_get_glyph_extents (hb_font_t *font,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
hb_glyph_extents_t *extents,
void *user_data HB_UNUSED)
{
IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
UINT16 gid = glyph;
DWRITE_GLYPH_METRICS metrics;
if (FAILED (dw_face->GetDesignGlyphMetrics (&gid, 1, &metrics)))
return false;
extents->x_bearing = font->em_scale_x (metrics.leftSideBearing);
extents->y_bearing = font->em_scale_y (metrics.verticalOriginY - metrics.topSideBearing);
extents->width = font->em_scale_x (metrics.advanceWidth - metrics.rightSideBearing) - extents->x_bearing;
extents->height = font->em_scale_y (metrics.verticalOriginY - metrics.advanceHeight + metrics.bottomSideBearing) - extents->y_bearing; // Magic
return true;
}
#ifndef HB_NO_DRAW
class GeometrySink : public IDWriteGeometrySink
{
hb_font_t *font;
hb_draw_session_t drawing;
public:
GeometrySink(hb_font_t *font,
hb_draw_funcs_t *draw_funcs,
void *draw_data)
: font (font), drawing ({draw_funcs, draw_data, font->slant}) {}
virtual ~GeometrySink() {}
HRESULT STDMETHODCALLTYPE Close() override { return S_OK; }
void STDMETHODCALLTYPE SetFillMode(D2D1_FILL_MODE) override {}
void STDMETHODCALLTYPE SetSegmentFlags(D2D1_PATH_SEGMENT) override {}
IFACEMETHOD(QueryInterface)(REFIID, void **) override { return E_NOINTERFACE; }
IFACEMETHOD_(ULONG, AddRef)() override { return 1; }
IFACEMETHOD_(ULONG, Release)() override { return 1; }
void STDMETHODCALLTYPE BeginFigure(D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN) override
{
drawing.move_to (font->em_scalef_x (startPoint.x), -font->em_scalef_y (startPoint.y));
}
void STDMETHODCALLTYPE AddBeziers(const D2D1_BEZIER_SEGMENT *beziers, UINT beziersCount) override
{
for (unsigned i = 0; i < beziersCount; ++i)
drawing.cubic_to (font->em_scalef_x (beziers[i].point1.x), -font->em_scalef_y (beziers[i].point1.y),
font->em_scalef_x (beziers[i].point2.x), -font->em_scalef_y (beziers[i].point2.y),
font->em_scalef_x (beziers[i].point3.x), -font->em_scalef_y (beziers[i].point3.y));
}
void STDMETHODCALLTYPE AddLines(const D2D1_POINT_2F *points, UINT pointsCount) override
{
for (unsigned i = 0; i < pointsCount; ++i)
drawing.line_to (font->em_scalef_x (points[i].x), -font->em_scalef_y (points[i].y));
}
void STDMETHODCALLTYPE EndFigure(D2D1_FIGURE_END) override
{
drawing.close_path ();
}
};
static void
hb_directwrite_draw_glyph (hb_font_t *font,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
hb_draw_funcs_t *draw_funcs, void *draw_data,
void *user_data)
{
IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
GeometrySink sink (font, draw_funcs, draw_data);
UINT16 gid = static_cast<UINT16>(glyph);
unsigned upem = font->face->get_upem();
(void) dw_face->GetGlyphRunOutline (upem,
&gid, nullptr, nullptr,
1,
false, false,
&sink);
}
#endif
static inline void free_static_directwrite_funcs ();
static struct hb_directwrite_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_directwrite_font_funcs_lazy_loader_t>
{
static hb_font_funcs_t *create ()
{
hb_font_funcs_t *funcs = hb_font_funcs_create ();
hb_font_funcs_set_nominal_glyphs_func (funcs, hb_directwrite_get_nominal_glyphs, nullptr, nullptr);
//hb_font_funcs_set_variation_glyph_func (funcs, hb_directwrite_get_variation_glyph, nullptr, nullptr);
hb_font_funcs_set_font_h_extents_func (funcs, hb_directwrite_get_font_h_extents, nullptr, nullptr);
hb_font_funcs_set_glyph_h_advances_func (funcs, hb_directwrite_get_glyph_h_advances, nullptr, nullptr);
#ifndef HB_NO_VERTICAL
hb_font_funcs_set_glyph_v_advances_func (funcs, hb_directwrite_get_glyph_v_advances, nullptr, nullptr);
hb_font_funcs_set_glyph_v_origin_func (funcs, hb_directwrite_get_glyph_v_origin, nullptr, nullptr);
#endif
#ifndef HB_NO_DRAW
hb_font_funcs_set_draw_glyph_func (funcs, hb_directwrite_draw_glyph, nullptr, nullptr);
#endif
hb_font_funcs_set_glyph_extents_func (funcs, hb_directwrite_get_glyph_extents, nullptr, nullptr);
#ifndef HB_NO_OT_FONT_GLYPH_NAMES
//hb_font_funcs_set_glyph_name_func (funcs, hb_directwrite_get_glyph_name, nullptr, nullptr);
//hb_font_funcs_set_glyph_from_name_func (funcs, hb_directwrite_get_glyph_from_name, nullptr, nullptr);
#endif
hb_font_funcs_make_immutable (funcs);
hb_atexit (free_static_directwrite_funcs);
return funcs;
}
} static_directwrite_funcs;
static inline
void free_static_directwrite_funcs ()
{
static_directwrite_funcs.free_instance ();
}
static hb_font_funcs_t *
_hb_directwrite_get_font_funcs ()
{
return static_directwrite_funcs.get_unconst ();
}
/**
* hb_directwrite_font_set_funcs:
* @font: #hb_font_t to work upon
*
* Configures the font-functions structure of the specified
* #hb_font_t font object to use DirectWrite font functions.
*
* In particular, you can use this function to configure an
* existing #hb_face_t face object for use with DirectWrite font
* functions even if that #hb_face_t face object was initially
* created with hb_face_create(), and therefore was not
* initially configured to use DirectWrite font functions.
*
* <note>Note: Internally, this function creates a DirectWrite font.
* </note>
*
* Since: 11.0.0
**/
void
hb_directwrite_font_set_funcs (hb_font_t *font)
{
IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
if (unlikely (!dw_face))
{
hb_font_set_funcs (font,
hb_font_funcs_get_empty (),
nullptr, nullptr);
return;
}
dw_face->AddRef ();
hb_font_set_funcs (font,
_hb_directwrite_get_font_funcs (),
nullptr, nullptr);
}
#undef MAX_GLYPHS
#endif

View file

@ -1,656 +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
*/
#include "hb.hh"
#ifdef HAVE_DIRECTWRITE
#include "hb-shaper-impl.hh"
#include "hb-directwrite.hh"
#include "hb-ms-feature-ranges.hh"
/*
* shaper face data
*/
hb_directwrite_face_data_t *
_hb_directwrite_shaper_face_data_create (hb_face_t *face)
{
hb_blob_t *blob = hb_face_reference_blob (face);
hb_directwrite_face_data_t *data = (hb_directwrite_face_data_t *) dw_face_create (blob, face->index);
hb_blob_destroy (blob);
return data;
}
void
_hb_directwrite_shaper_face_data_destroy (hb_directwrite_face_data_t *data)
{
((IDWriteFontFace *) data)->Release ();
}
/*
* shaper font data
*/
struct hb_directwrite_font_data_t {};
hb_directwrite_font_data_t *
_hb_directwrite_shaper_font_data_create (hb_font_t *font)
{
IDWriteFontFace *fontFace = (IDWriteFontFace *) (const void *) font->face->data.directwrite;
/*
* Set up variations.
*/
IDWriteFontFace5 *fontFaceVariations = nullptr;
{
IDWriteFontFace5 *fontFace5;
if (SUCCEEDED (fontFace->QueryInterface (__uuidof (IDWriteFontFace5), (void **) &fontFace5)))
{
IDWriteFontResource *fontResource;
if (SUCCEEDED (fontFace5->GetFontResource (&fontResource)))
{
hb_vector_t<DWRITE_FONT_AXIS_VALUE> axis_values;
if (likely (axis_values.resize_exact (font->num_coords)))
{
for (unsigned int i = 0; i < font->num_coords; i++)
{
hb_ot_var_axis_info_t info;
unsigned int c = 1;
hb_ot_var_get_axis_infos (font->face, i, &c, &info);
axis_values[i].axisTag = (DWRITE_FONT_AXIS_TAG) hb_uint32_swap (info.tag);
axis_values[i].value = i < font->num_coords ?
hb_clamp (font->design_coords[i], info.min_value, info.max_value) :
info.default_value;
}
fontResource->CreateFontFace (DWRITE_FONT_SIMULATIONS::DWRITE_FONT_SIMULATIONS_NONE,
axis_values.arrayZ, axis_values.length, &fontFaceVariations);
}
fontResource->Release ();
}
fontFace5->Release ();
}
}
return (hb_directwrite_font_data_t *) fontFaceVariations;
}
void
_hb_directwrite_shaper_font_data_destroy (hb_directwrite_font_data_t *data)
{
((IDWriteFontFace *) (const void *) data)->Release ();
}
// Most of TextAnalysis is originally written by Bas Schouten for Mozilla project
// but now is relicensed to MIT for HarfBuzz use
class TextAnalysis : public IDWriteTextAnalysisSource, public IDWriteTextAnalysisSink
{
private:
hb_reference_count_t mRefCount;
public:
IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject)
{ return S_OK; }
IFACEMETHOD_ (ULONG, AddRef) ()
{
return mRefCount.inc () + 1;
}
IFACEMETHOD_ (ULONG, Release) ()
{
signed refCount = mRefCount.dec () - 1;
assert (refCount >= 0);
if (refCount)
return refCount;
delete this;
return 0;
}
// A single contiguous run of characters containing the same analysis
// results.
struct Run
{
uint32_t mTextStart; // starting text position of this run
uint32_t mTextLength; // number of contiguous code units covered
uint32_t mGlyphStart; // starting glyph in the glyphs array
uint32_t mGlyphCount; // number of glyphs associated with this run
// text
DWRITE_SCRIPT_ANALYSIS mScript;
uint8_t mBidiLevel;
bool mIsSideways;
bool ContainsTextPosition (uint32_t aTextPosition) const
{
return aTextPosition >= mTextStart &&
aTextPosition < mTextStart + mTextLength;
}
Run *nextRun;
};
public:
TextAnalysis (const wchar_t* text, uint32_t textLength,
const wchar_t* localeName, DWRITE_READING_DIRECTION readingDirection)
: mTextLength (textLength), mText (text), mLocaleName (localeName),
mReadingDirection (readingDirection), mCurrentRun (nullptr)
{
mRefCount.init ();
}
virtual ~TextAnalysis ()
{
// delete runs, except mRunHead which is part of the TextAnalysis object
for (Run *run = mRunHead.nextRun; run;)
{
Run *origRun = run;
run = run->nextRun;
delete origRun;
}
}
STDMETHODIMP
GenerateResults (IDWriteTextAnalyzer* textAnalyzer, Run **runHead)
{
// Analyzes the text using the script analyzer and returns
// the result as a series of runs.
HRESULT hr = S_OK;
// Initially start out with one result that covers the entire range.
// This result will be subdivided by the analysis processes.
mRunHead.mTextStart = 0;
mRunHead.mTextLength = mTextLength;
mRunHead.mBidiLevel =
(mReadingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
mRunHead.nextRun = nullptr;
mCurrentRun = &mRunHead;
// Call each of the analyzers in sequence, recording their results.
if (SUCCEEDED (hr = textAnalyzer->AnalyzeScript (this, 0, mTextLength, this)))
*runHead = &mRunHead;
return hr;
}
// IDWriteTextAnalysisSource implementation
IFACEMETHODIMP
GetTextAtPosition (uint32_t textPosition,
OUT wchar_t const** textString,
OUT uint32_t* textLength)
{
if (textPosition >= mTextLength)
{
// No text at this position, valid query though.
*textString = nullptr;
*textLength = 0;
}
else
{
*textString = mText + textPosition;
*textLength = mTextLength - textPosition;
}
return S_OK;
}
IFACEMETHODIMP
GetTextBeforePosition (uint32_t textPosition,
OUT wchar_t const** textString,
OUT uint32_t* textLength)
{
if (textPosition == 0 || textPosition > mTextLength)
{
// Either there is no text before here (== 0), or this
// is an invalid position. The query is considered valid though.
*textString = nullptr;
*textLength = 0;
}
else
{
*textString = mText;
*textLength = textPosition;
}
return S_OK;
}
IFACEMETHODIMP_ (DWRITE_READING_DIRECTION)
GetParagraphReadingDirection () { return mReadingDirection; }
IFACEMETHODIMP GetLocaleName (uint32_t textPosition, uint32_t* textLength,
wchar_t const** localeName)
{ return S_OK; }
IFACEMETHODIMP
GetNumberSubstitution (uint32_t textPosition,
OUT uint32_t* textLength,
OUT IDWriteNumberSubstitution** numberSubstitution)
{
// We do not support number substitution.
*numberSubstitution = nullptr;
*textLength = mTextLength - textPosition;
return S_OK;
}
// IDWriteTextAnalysisSink implementation
IFACEMETHODIMP
SetScriptAnalysis (uint32_t textPosition, uint32_t textLength,
DWRITE_SCRIPT_ANALYSIS const* scriptAnalysis)
{
SetCurrentRun (textPosition);
SplitCurrentRun (textPosition);
while (textLength > 0)
{
Run *run = FetchNextRun (&textLength);
run->mScript = *scriptAnalysis;
}
return S_OK;
}
IFACEMETHODIMP
SetLineBreakpoints (uint32_t textPosition,
uint32_t textLength,
const DWRITE_LINE_BREAKPOINT* lineBreakpoints)
{ return S_OK; }
IFACEMETHODIMP SetBidiLevel (uint32_t textPosition, uint32_t textLength,
uint8_t explicitLevel, uint8_t resolvedLevel)
{ return S_OK; }
IFACEMETHODIMP
SetNumberSubstitution (uint32_t textPosition, uint32_t textLength,
IDWriteNumberSubstitution* numberSubstitution)
{ return S_OK; }
protected:
Run *FetchNextRun (IN OUT uint32_t* textLength)
{
// Used by the sink setters, this returns a reference to the next run.
// Position and length are adjusted to now point after the current run
// being returned.
Run *origRun = mCurrentRun;
// Split the tail if needed (the length remaining is less than the
// current run's size).
if (*textLength < mCurrentRun->mTextLength)
SplitCurrentRun (mCurrentRun->mTextStart + *textLength);
else
// Just advance the current run.
mCurrentRun = mCurrentRun->nextRun;
*textLength -= origRun->mTextLength;
// Return a reference to the run that was just current.
return origRun;
}
void SetCurrentRun (uint32_t textPosition)
{
// Move the current run to the given position.
// Since the analyzers generally return results in a forward manner,
// this will usually just return early. If not, find the
// corresponding run for the text position.
if (mCurrentRun && mCurrentRun->ContainsTextPosition (textPosition))
return;
for (Run *run = &mRunHead; run; run = run->nextRun)
if (run->ContainsTextPosition (textPosition))
{
mCurrentRun = run;
return;
}
assert (0); // We should always be able to find the text position in one of our runs
}
void SplitCurrentRun (uint32_t splitPosition)
{
if (!mCurrentRun)
{
assert (0); // SplitCurrentRun called without current run
// Shouldn't be calling this when no current run is set!
return;
}
// Split the current run.
if (splitPosition <= mCurrentRun->mTextStart)
{
// No need to split, already the start of a run
// or before it. Usually the first.
return;
}
Run *newRun = new Run;
*newRun = *mCurrentRun;
// Insert the new run in our linked list.
newRun->nextRun = mCurrentRun->nextRun;
mCurrentRun->nextRun = newRun;
// Adjust runs' text positions and lengths.
uint32_t splitPoint = splitPosition - mCurrentRun->mTextStart;
newRun->mTextStart += splitPoint;
newRun->mTextLength -= splitPoint;
mCurrentRun->mTextLength = splitPoint;
mCurrentRun = newRun;
}
protected:
// Input
// (weak references are fine here, since this class is a transient
// stack-based helper that doesn't need to copy data)
uint32_t mTextLength;
const wchar_t* mText;
const wchar_t* mLocaleName;
DWRITE_READING_DIRECTION mReadingDirection;
// Current processing state.
Run *mCurrentRun;
// Output is a list of runs starting here
Run mRunHead;
};
/*
* shaper
*/
hb_bool_t
_hb_directwrite_shape (hb_shape_plan_t *shape_plan,
hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features)
{
IDWriteFontFace *fontFace = (IDWriteFontFace *) (const void *) font->data.directwrite;
auto *global = get_directwrite_global ();
if (unlikely (!global))
return false;
IDWriteFactory *dwriteFactory = global->dwriteFactory;
IDWriteTextAnalyzer* analyzer;
dwriteFactory->CreateTextAnalyzer (&analyzer);
unsigned int scratch_size;
hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
#define ALLOCATE_ARRAY(Type, name, len) \
Type *name = (Type *) scratch; \
do { \
unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
assert (_consumed <= scratch_size); \
scratch += _consumed; \
scratch_size -= _consumed; \
} while (0)
#define utf16_index() var1.u32
ALLOCATE_ARRAY (wchar_t, textString, buffer->len * 2);
unsigned int chars_len = 0;
for (unsigned int i = 0; i < buffer->len; i++)
{
hb_codepoint_t c = buffer->info[i].codepoint;
buffer->info[i].utf16_index () = chars_len;
if (likely (c <= 0xFFFFu))
textString[chars_len++] = c;
else if (unlikely (c > 0x10FFFFu))
textString[chars_len++] = 0xFFFDu;
else
{
textString[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
textString[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1u << 10) - 1));
}
}
ALLOCATE_ARRAY (WORD, log_clusters, chars_len);
/* Need log_clusters to assign features. */
chars_len = 0;
for (unsigned int i = 0; i < buffer->len; i++)
{
hb_codepoint_t c = buffer->info[i].codepoint;
unsigned int cluster = buffer->info[i].cluster;
log_clusters[chars_len++] = cluster;
if (hb_in_range (c, 0x10000u, 0x10FFFFu))
log_clusters[chars_len++] = cluster; /* Surrogates. */
}
DWRITE_READING_DIRECTION readingDirection;
readingDirection = buffer->props.direction ?
DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
/*
* There's an internal 16-bit limit on some things inside the analyzer,
* but we never attempt to shape a word longer than 64K characters
* in a single gfxShapedWord, so we cannot exceed that limit.
*/
uint32_t textLength = chars_len;
TextAnalysis analysis (textString, textLength, nullptr, readingDirection);
TextAnalysis::Run *runHead;
HRESULT hr;
hr = analysis.GenerateResults (analyzer, &runHead);
#define FAIL(...) \
HB_STMT_START { \
DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \
return false; \
} HB_STMT_END
if (FAILED (hr))
FAIL ("Analyzer failed to generate results.");
uint32_t maxGlyphCount = 3 * textLength / 2 + 16;
uint32_t glyphCount;
bool isRightToLeft = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
const wchar_t localeName[20] = {0};
if (buffer->props.language)
mbstowcs ((wchar_t*) localeName,
hb_language_to_string (buffer->props.language), 20);
/*
* Set up features.
*/
static_assert ((sizeof (DWRITE_TYPOGRAPHIC_FEATURES) == sizeof (hb_ms_features_t)), "");
static_assert ((sizeof (DWRITE_FONT_FEATURE) == sizeof (hb_ms_feature_t)), "");
hb_vector_t<hb_ms_features_t *> range_features;
hb_vector_t<uint32_t> range_char_counts;
// https://github.com/harfbuzz/harfbuzz/pull/5114
// The data allocated by these two vectors are used by the above two, so they
// should remain alive as long as the above two are.
hb_vector_t<hb_ms_feature_t> feature_records;
hb_vector_t<hb_ms_range_record_t> range_records;
if (num_features)
{
if (hb_ms_setup_features (features, num_features, feature_records, range_records))
{
hb_ms_make_feature_ranges (feature_records,
range_records,
0,
chars_len,
log_clusters,
range_features,
range_char_counts);
}
}
uint16_t* clusterMap;
clusterMap = new uint16_t[textLength];
DWRITE_SHAPING_TEXT_PROPERTIES* textProperties;
textProperties = new DWRITE_SHAPING_TEXT_PROPERTIES[textLength];
retry_getglyphs:
uint16_t* glyphIndices = new uint16_t[maxGlyphCount];
DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties;
glyphProperties = new DWRITE_SHAPING_GLYPH_PROPERTIES[maxGlyphCount];
hr = analyzer->GetGlyphs (textString,
chars_len,
fontFace,
false,
isRightToLeft,
&runHead->mScript,
localeName,
nullptr,
(const DWRITE_TYPOGRAPHIC_FEATURES**) range_features.arrayZ,
range_char_counts.arrayZ,
range_features.length,
maxGlyphCount,
clusterMap,
textProperties,
glyphIndices,
glyphProperties,
&glyphCount);
if (unlikely (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER)))
{
delete [] glyphIndices;
delete [] glyphProperties;
maxGlyphCount *= 2;
goto retry_getglyphs;
}
if (FAILED (hr))
FAIL ("Analyzer failed to get glyphs.");
float* glyphAdvances = new float[maxGlyphCount];
DWRITE_GLYPH_OFFSET* glyphOffsets = new DWRITE_GLYPH_OFFSET[maxGlyphCount];
/* The -2 in the following is to compensate for possible
* alignment needed after the WORD array. sizeof (WORD) == 2. */
unsigned int glyphs_size = (scratch_size * sizeof (int) - 2)
/ (sizeof (WORD) +
sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES) +
sizeof (int) +
sizeof (DWRITE_GLYPH_OFFSET) +
sizeof (uint32_t));
ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size);
#undef ALLOCATE_ARRAY
unsigned fontEmSize = font->face->get_upem ();
float x_mult = font->x_multf;
float y_mult = font->y_multf;
hr = analyzer->GetGlyphPlacements (textString,
clusterMap,
textProperties,
chars_len,
glyphIndices,
glyphProperties,
glyphCount,
fontFace,
fontEmSize,
false,
isRightToLeft,
&runHead->mScript,
localeName,
(const DWRITE_TYPOGRAPHIC_FEATURES**) range_features.arrayZ,
range_char_counts.arrayZ,
range_features.length,
glyphAdvances,
glyphOffsets);
if (FAILED (hr))
FAIL ("Analyzer failed to get glyph placements.");
/* Ok, we've got everything we need, now compose output buffer,
* very, *very*, carefully! */
/* Calculate visual-clusters. That's what we ship. */
for (unsigned int i = 0; i < glyphCount; i++)
vis_clusters[i] = (uint32_t) -1;
for (unsigned int i = 0; i < buffer->len; i++)
{
uint32_t *p =
&vis_clusters[log_clusters[buffer->info[i].utf16_index ()]];
*p = hb_min (*p, buffer->info[i].cluster);
}
for (unsigned int i = 1; i < glyphCount; i++)
if (vis_clusters[i] == (uint32_t) -1)
vis_clusters[i] = vis_clusters[i - 1];
#undef utf16_index
if (unlikely (!buffer->ensure (glyphCount)))
FAIL ("Buffer in error");
#undef FAIL
/* Set glyph infos */
buffer->len = 0;
for (unsigned int i = 0; i < glyphCount; i++)
{
hb_glyph_info_t *info = &buffer->info[buffer->len++];
info->codepoint = glyphIndices[i];
info->cluster = vis_clusters[i];
/* The rest is crap. Let's store position info there for now. */
info->mask = glyphAdvances[i];
info->var1.i32 = glyphOffsets[i].advanceOffset;
info->var2.i32 = glyphOffsets[i].ascenderOffset;
}
/* Set glyph positions */
buffer->clear_positions ();
for (unsigned int i = 0; i < glyphCount; i++)
{
hb_glyph_info_t *info = &buffer->info[i];
hb_glyph_position_t *pos = &buffer->pos[i];
/* TODO vertical */
pos->x_advance = round (x_mult * (int32_t) info->mask);
pos->x_offset = round (x_mult * (isRightToLeft ? -info->var1.i32 : info->var1.i32));
pos->y_offset = round (y_mult * info->var2.i32);
}
if (isRightToLeft) hb_buffer_reverse (buffer);
buffer->clear_glyph_flags ();
buffer->unsafe_to_break ();
delete [] clusterMap;
delete [] glyphIndices;
delete [] textProperties;
delete [] glyphProperties;
delete [] glyphAdvances;
delete [] glyphOffsets;
/* Wow, done! */
return true;
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -27,45 +27,20 @@
#include "hb.h"
#include <dwrite_3.h>
HB_BEGIN_DECLS
HB_EXTERN hb_face_t *
hb_directwrite_face_create (IDWriteFontFace *dw_face);
HB_EXTERN hb_face_t *
hb_directwrite_face_create_from_file_or_fail (const char *file_name,
unsigned int index);
HB_EXTERN hb_face_t *
hb_directwrite_face_create_from_blob_or_fail (hb_blob_t *blob,
unsigned int index);
HB_EXTERN IDWriteFontFace *
hb_directwrite_face_get_dw_font_face (hb_face_t *face);
HB_EXTERN hb_font_t *
hb_directwrite_font_create (IDWriteFontFace *dw_face);
HB_EXTERN IDWriteFontFace *
hb_directwrite_font_get_dw_font_face (hb_font_t *font);
HB_EXTERN void
hb_directwrite_font_set_funcs (hb_font_t *font);
#ifndef HB_DISABLE_DEPRECATED
HB_DEPRECATED_FOR (hb_directwrite_face_get_dw_font_face)
HB_EXTERN IDWriteFontFace *
hb_directwrite_face_get_font_face (hb_face_t *face);
HB_DEPRECATED
HB_EXTERN hb_font_t *
hb_directwrite_font_create (IDWriteFont *dw_font);
HB_EXTERN IDWriteFont *
hb_directwrite_font_get_dw_font (hb_font_t *font);
#endif
HB_END_DECLS
#endif /* HB_DIRECTWRITE_H */

View file

@ -1,223 +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_DIRECTWRITE_HH
#define HB_DIRECTWRITE_HH
#include "hb.hh"
#include "hb-directwrite.h"
#include "hb-mutex.hh"
#include "hb-map.hh"
/*
* DirectWrite font stream helpers
*/
// Have a look at to NativeFontResourceDWrite.cpp in Mozilla
/* Declare object creator for dynamic support of DWRITE */
typedef HRESULT (WINAPI *t_DWriteCreateFactory)(
DWRITE_FACTORY_TYPE factoryType,
REFIID iid,
IUnknown **factory
);
class DWriteFontFileLoader : public IDWriteFontFileLoader
{
private:
hb_reference_count_t mRefCount;
hb_mutex_t mutex;
hb_hashmap_t<uint64_t, IDWriteFontFileStream *> mFontStreams;
uint64_t mNextFontFileKey = 0;
public:
DWriteFontFileLoader ()
{
mRefCount.init ();
}
uint64_t RegisterFontFileStream (IDWriteFontFileStream *fontFileStream)
{
fontFileStream->AddRef ();
hb_lock_t lock {mutex};
mFontStreams.set (mNextFontFileKey, fontFileStream);
return mNextFontFileKey++;
}
void UnregisterFontFileStream (uint64_t fontFileKey)
{
hb_lock_t lock {mutex};
IDWriteFontFileStream *stream = mFontStreams.get (fontFileKey);
if (stream)
{
mFontStreams.del (fontFileKey);
stream->Release ();
}
}
// IUnknown interface
IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject)
{ return S_OK; }
IFACEMETHOD_ (ULONG, AddRef) ()
{
return mRefCount.inc () + 1;
}
IFACEMETHOD_ (ULONG, Release) ()
{
signed refCount = mRefCount.dec () - 1;
assert (refCount >= 0);
if (refCount)
return refCount;
delete this;
return 0;
}
// IDWriteFontFileLoader methods
virtual HRESULT STDMETHODCALLTYPE
CreateStreamFromKey (void const* fontFileReferenceKey,
uint32_t fontFileReferenceKeySize,
OUT IDWriteFontFileStream** fontFileStream)
{
if (fontFileReferenceKeySize != sizeof (uint64_t))
return E_INVALIDARG;
uint64_t fontFileKey = * (uint64_t *) fontFileReferenceKey;
IDWriteFontFileStream *stream = mFontStreams.get (fontFileKey);
if (!stream)
return E_FAIL;
stream->AddRef ();
*fontFileStream = stream;
return S_OK;
}
virtual ~DWriteFontFileLoader()
{
for (auto v : mFontStreams.values ())
v->Release ();
}
};
class DWriteFontFileStream : public IDWriteFontFileStream
{
private:
hb_reference_count_t mRefCount;
hb_blob_t *mBlob;
uint8_t *mData;
unsigned mSize;
DWriteFontFileLoader *mLoader;
public:
uint64_t fontFileKey;
public:
DWriteFontFileStream (hb_blob_t *blob);
// IUnknown interface
IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject)
{ return S_OK; }
IFACEMETHOD_ (ULONG, AddRef) ()
{
return mRefCount.inc () + 1;
}
IFACEMETHOD_ (ULONG, Release) ()
{
signed refCount = mRefCount.dec () - 1;
assert (refCount >= 0);
if (refCount)
return refCount;
delete this;
return 0;
}
// IDWriteFontFileStream methods
virtual HRESULT STDMETHODCALLTYPE
ReadFileFragment (void const** fragmentStart,
UINT64 fileOffset,
UINT64 fragmentSize,
OUT void** fragmentContext)
{
// We are required to do bounds checking.
if (fileOffset + fragmentSize > mSize) return E_FAIL;
// truncate the 64 bit fileOffset to size_t sized index into mData
size_t index = static_cast<size_t> (fileOffset);
// We should be alive for the duration of this.
*fragmentStart = &mData[index];
*fragmentContext = nullptr;
return S_OK;
}
virtual void STDMETHODCALLTYPE
ReleaseFileFragment (void* fragmentContext) {}
virtual HRESULT STDMETHODCALLTYPE
GetFileSize (OUT UINT64* fileSize)
{
*fileSize = mSize;
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE
GetLastWriteTime (OUT UINT64* lastWriteTime) { return E_NOTIMPL; }
virtual ~DWriteFontFileStream();
};
struct hb_directwrite_global_t
{
hb_directwrite_global_t ()
{
HRESULT hr = DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
(IUnknown**) &dwriteFactory);
if (unlikely (hr != S_OK))
return;
fontFileLoader = new DWriteFontFileLoader ();
dwriteFactory->RegisterFontFileLoader (fontFileLoader);
success = true;
}
~hb_directwrite_global_t ()
{
if (fontFileLoader)
fontFileLoader->Release ();
if (dwriteFactory)
dwriteFactory->Release ();
}
bool success = false;
IDWriteFactory *dwriteFactory;
DWriteFontFileLoader *fontFileLoader;
};
HB_INTERNAL hb_directwrite_global_t *
get_directwrite_global ();
HB_INTERNAL IDWriteFontFace *
dw_face_create (hb_blob_t *blob, unsigned index);
#endif /* HB_DIRECTWRITE_HH */

View file

@ -41,16 +41,9 @@ HB_BEGIN_DECLS
* @path_start_y: Y component of the start of current path
* @current_x: X component of current point
* @current_y: Y component of current point
* @slant_xy: Slanting factor for synthetic oblique, Since: 11.0.0
*
* Current drawing state.
*
* The @slant_xy is a slanting factor for synthetic oblique. If the font's
* oblique angle is not 0, this factor is used to slant the drawing. For
* fonts with uniform x and y scales, this factor is calculated as
* tan(oblique_angle). For fonts with non-uniform scales, this factor is
* calculated as tan(oblique_angle) * x_scale / y_scale, or 0 if y_scale is 0.
*
* Since: 4.0.0
**/
typedef struct hb_draw_state_t {
@ -62,8 +55,6 @@ typedef struct hb_draw_state_t {
float current_x;
float current_y;
float slant_xy;
/*< private >*/
hb_var_num_t reserved1;
hb_var_num_t reserved2;
@ -71,6 +62,7 @@ typedef struct hb_draw_state_t {
hb_var_num_t reserved4;
hb_var_num_t reserved5;
hb_var_num_t reserved6;
hb_var_num_t reserved7;
} hb_draw_state_t;
/**
@ -78,7 +70,7 @@ typedef struct hb_draw_state_t {
*
* The default #hb_draw_state_t at the start of glyph drawing.
*/
#define HB_DRAW_STATE_DEFAULT {0, 0.f, 0.f, 0.f, 0.f, 0.f, {0.}, {0.}, {0.}, {0.}, {0.}, {0.}}
#define HB_DRAW_STATE_DEFAULT {0, 0.f, 0.f, 0.f, 0.f, {0.}, {0.}, {0.}, {0.}, {0.}, {0.}, {0.}}
/**

View file

@ -99,10 +99,6 @@ struct hb_draw_funcs_t
float to_x, float to_y)
{
if (unlikely (st.path_open)) close_path (draw_data, st);
if (st.slant_xy)
to_x += to_y * st.slant_xy;
st.current_x = to_x;
st.current_y = to_y;
}
@ -113,12 +109,7 @@ struct hb_draw_funcs_t
float to_x, float to_y)
{
if (unlikely (!st.path_open)) start_path (draw_data, st);
if (st.slant_xy)
to_x += to_y * st.slant_xy;
emit_line_to (draw_data, st, to_x, to_y);
st.current_x = to_x;
st.current_y = to_y;
}
@ -130,15 +121,7 @@ struct hb_draw_funcs_t
float to_x, float to_y)
{
if (unlikely (!st.path_open)) start_path (draw_data, st);
if (st.slant_xy)
{
control_x += control_y * st.slant_xy;
to_x += to_y * st.slant_xy;
}
emit_quadratic_to (draw_data, st, control_x, control_y, to_x, to_y);
st.current_x = to_x;
st.current_y = to_y;
}
@ -151,16 +134,7 @@ struct hb_draw_funcs_t
float to_x, float to_y)
{
if (unlikely (!st.path_open)) start_path (draw_data, st);
if (st.slant_xy)
{
control1_x += control1_y * st.slant_xy;
control2_x += control2_y * st.slant_xy;
to_x += to_y * st.slant_xy;
}
emit_cubic_to (draw_data, st, control1_x, control1_y, control2_x, control2_y, to_x, to_y);
st.current_x = to_x;
st.current_y = to_y;
}
@ -194,32 +168,46 @@ DECLARE_NULL_INSTANCE (hb_draw_funcs_t);
struct hb_draw_session_t
{
hb_draw_session_t (hb_draw_funcs_t *funcs_, void *draw_data_, float slant_xy = 0.f)
: funcs {funcs_}, draw_data {draw_data_}, st HB_DRAW_STATE_DEFAULT
{ st.slant_xy = slant_xy; }
hb_draw_session_t (hb_draw_funcs_t *funcs_, void *draw_data_, float slant_ = 0.f)
: slant {slant_}, not_slanted {slant == 0.f},
funcs {funcs_}, draw_data {draw_data_}, st HB_DRAW_STATE_DEFAULT
{}
~hb_draw_session_t () { close_path (); }
HB_ALWAYS_INLINE
void move_to (float to_x, float to_y)
{
funcs->move_to (draw_data, st,
to_x, to_y);
if (likely (not_slanted))
funcs->move_to (draw_data, st,
to_x, to_y);
else
funcs->move_to (draw_data, st,
to_x + to_y * slant, to_y);
}
HB_ALWAYS_INLINE
void line_to (float to_x, float to_y)
{
funcs->line_to (draw_data, st,
to_x, to_y);
if (likely (not_slanted))
funcs->line_to (draw_data, st,
to_x, to_y);
else
funcs->line_to (draw_data, st,
to_x + to_y * slant, to_y);
}
void
HB_ALWAYS_INLINE
quadratic_to (float control_x, float control_y,
float to_x, float to_y)
{
funcs->quadratic_to (draw_data, st,
control_x, control_y,
to_x, to_y);
if (likely (not_slanted))
funcs->quadratic_to (draw_data, st,
control_x, control_y,
to_x, to_y);
else
funcs->quadratic_to (draw_data, st,
control_x + control_y * slant, control_y,
to_x + to_y * slant, to_y);
}
void
HB_ALWAYS_INLINE
@ -227,10 +215,16 @@ struct hb_draw_session_t
float control2_x, float control2_y,
float to_x, float to_y)
{
funcs->cubic_to (draw_data, st,
control1_x, control1_y,
control2_x, control2_y,
to_x, to_y);
if (likely (not_slanted))
funcs->cubic_to (draw_data, st,
control1_x, control1_y,
control2_x, control2_y,
to_x, to_y);
else
funcs->cubic_to (draw_data, st,
control1_x + control1_y * slant, control1_y,
control2_x + control2_y * slant, control2_y,
to_x + to_y * slant, to_y);
}
HB_ALWAYS_INLINE
void close_path ()
@ -239,6 +233,8 @@ struct hb_draw_session_t
}
public:
float slant;
bool not_slanted;
hb_draw_funcs_t *funcs;
void *draw_data;
hb_draw_state_t st;

View file

@ -34,16 +34,6 @@
#include "hb-ot-face.hh"
#include "hb-ot-cmap-table.hh"
#ifdef HAVE_FREETYPE
#include "hb-ft.h"
#endif
#ifdef HAVE_CORETEXT
#include "hb-coretext.h"
#endif
#ifdef HAVE_DIRECTWRITE
#include "hb-directwrite.h"
#endif
/**
* SECTION:hb-face
@ -82,14 +72,14 @@ hb_face_count (hb_blob_t *blob)
if (unlikely (!blob))
return 0;
hb_sanitize_context_t c (blob);
/* TODO We shouldn't be sanitizing blob. Port to run sanitizer and return if not sane. */
/* Make API signature const after. */
hb_blob_t *sanitized = hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob));
const OT::OpenTypeFontFile& ot = *sanitized->as<OT::OpenTypeFontFile> ();
unsigned int ret = ot.get_face_count ();
hb_blob_destroy (sanitized);
const char *start = hb_blob_get_data (blob, nullptr);
auto *ot = reinterpret_cast<OT::OpenTypeFontFile *> (const_cast<char *> (start));
if (unlikely (!ot->sanitize (&c)))
return 0;
return ot->get_face_count ();
return ret;
}
/*
@ -328,209 +318,7 @@ hb_face_create_from_file_or_fail (const char *file_name,
return face;
}
static struct supported_face_loaders_t {
char name[16];
hb_face_t * (*from_file) (const char *font_file, unsigned face_index);
hb_face_t * (*from_blob) (hb_blob_t *blob, unsigned face_index);
} supported_face_loaders[] =
{
{"ot",
#ifndef HB_NO_OPEN
hb_face_create_from_file_or_fail,
#else
nullptr,
#endif
hb_face_create_or_fail
},
#ifdef HAVE_FREETYPE
{"ft",
hb_ft_face_create_from_file_or_fail,
hb_ft_face_create_from_blob_or_fail
},
#endif
#ifdef HAVE_CORETEXT
{"coretext",
hb_coretext_face_create_from_file_or_fail,
hb_coretext_face_create_from_blob_or_fail
},
#endif
#ifdef HAVE_DIRECTWRITE
{"directwrite",
hb_directwrite_face_create_from_file_or_fail,
hb_directwrite_face_create_from_blob_or_fail
},
#endif
};
static const char *get_default_loader_name ()
{
static hb_atomic_t<const char *> static_loader_name;
const char *loader_name = static_loader_name.get_acquire ();
if (!loader_name)
{
loader_name = getenv ("HB_FACE_LOADER");
if (!loader_name)
loader_name = "";
if (!static_loader_name.cmpexch (nullptr, loader_name))
loader_name = static_loader_name.get_acquire ();
}
return loader_name;
}
/**
* hb_face_create_from_file_or_fail_using:
* @file_name: A font filename
* @index: The index of the face within the file
* @loader_name: (nullable): The name of the loader to use, or `NULL`
*
* A thin wrapper around the face loader functions registered with HarfBuzz.
* If @loader_name is `NULL` or the empty string, the first available loader
* is used.
*
* For example, the FreeType ("ft") loader might be able to load
* WOFF and WOFF2 files if FreeType is built with those features,
* whereas the OpenType ("ot") loader will not.
*
* Return value: (transfer full): The new face object, or `NULL` if
* the file cannot be read or the loader fails to load the face.
*
* Since: 11.0.0
**/
hb_face_t *
hb_face_create_from_file_or_fail_using (const char *file_name,
unsigned int index,
const char *loader_name)
{
// Duplicated in hb_face_create_or_fail_using
bool retry = false;
if (!loader_name || !*loader_name)
{
loader_name = get_default_loader_name ();
retry = true;
}
if (loader_name && !*loader_name) loader_name = nullptr;
retry:
for (unsigned i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++)
{
if (!loader_name || (supported_face_loaders[i].from_file && !strcmp (supported_face_loaders[i].name, loader_name)))
return supported_face_loaders[i].from_file (file_name, index);
}
if (retry)
{
retry = false;
loader_name = nullptr;
goto retry;
}
return nullptr;
}
/**
* hb_face_create_or_fail_using:
* @blob: #hb_blob_t to work upon
* @index: The index of the face within @blob
* @loader_name: (nullable): The name of the loader to use, or `NULL`
*
* A thin wrapper around the face loader functions registered with HarfBuzz.
* If @loader_name is `NULL` or the empty string, the first available loader
* is used.
*
* For example, the FreeType ("ft") loader might be able to load
* WOFF and WOFF2 files if FreeType is built with those features,
* whereas the OpenType ("ot") loader will not.
*
* Return value: (transfer full): The new face object, or `NULL` if
* the loader fails to load the face.
*
* Since: 11.0.0
**/
hb_face_t *
hb_face_create_or_fail_using (hb_blob_t *blob,
unsigned int index,
const char *loader_name)
{
// Duplicated in hb_face_create_from_file_or_fail_using
bool retry = false;
if (!loader_name || !*loader_name)
{
loader_name = get_default_loader_name ();
retry = true;
}
if (loader_name && !*loader_name) loader_name = nullptr;
retry:
for (unsigned i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++)
{
if (!loader_name || (supported_face_loaders[i].from_blob && !strcmp (supported_face_loaders[i].name, loader_name)))
return supported_face_loaders[i].from_blob (blob, index);
}
if (retry)
{
retry = false;
loader_name = nullptr;
goto retry;
}
return nullptr;
}
static inline void free_static_face_loader_list ();
static const char * const nil_face_loader_list[] = {nullptr};
static struct hb_face_loader_list_lazy_loader_t : hb_lazy_loader_t<const char *,
hb_face_loader_list_lazy_loader_t>
{
static const char ** create ()
{
const char **face_loader_list = (const char **) hb_calloc (1 + ARRAY_LENGTH (supported_face_loaders), sizeof (const char *));
if (unlikely (!face_loader_list))
return nullptr;
unsigned i;
for (i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++)
face_loader_list[i] = supported_face_loaders[i].name;
face_loader_list[i] = nullptr;
hb_atexit (free_static_face_loader_list);
return face_loader_list;
}
static void destroy (const char **l)
{ hb_free (l); }
static const char * const * get_null ()
{ return nil_face_loader_list; }
} static_face_loader_list;
static inline
void free_static_face_loader_list ()
{
static_face_loader_list.free_instance ();
}
/**
* hb_face_list_loaders:
*
* Retrieves the list of face loaders supported by HarfBuzz.
*
* Return value: (transfer none) (array zero-terminated=1): a
* `NULL`-terminated array of supported face loaders
* constant strings. The returned array is owned by HarfBuzz
* and should not be modified or freed.
*
* Since: 11.0.0
**/
const char **
hb_face_list_loaders ()
{
return static_face_loader_list.get_unconst ();
}
#endif
/**
* hb_face_get_empty:
@ -672,7 +460,7 @@ hb_face_make_immutable (hb_face_t *face)
* Since: 0.9.2
**/
hb_bool_t
hb_face_is_immutable (hb_face_t *face)
hb_face_is_immutable (const hb_face_t *face)
{
return hb_object_is_immutable (face);
}
@ -734,15 +522,11 @@ hb_face_reference_blob (hb_face_t *face)
for (unsigned offset = 0; offset < total_count; offset += count)
{
hb_face_get_table_tags (face, offset, &count, tags);
if (unlikely (!count))
break; // Allocation error
for (unsigned i = 0; i < count; i++)
{
if (unlikely (!tags[i]))
continue;
hb_blob_t *table = hb_face_reference_table (face, tags[i]);
hb_face_builder_add_table (builder, tags[i], table);
hb_blob_destroy (table);
hb_blob_t *table = hb_face_reference_table (face, tags[i]);
hb_face_builder_add_table (builder, tags[i], table);
hb_blob_destroy (table);
}
}

View file

@ -63,24 +63,10 @@ HB_EXTERN hb_face_t *
hb_face_create_or_fail (hb_blob_t *blob,
unsigned int index);
HB_EXTERN hb_face_t *
hb_face_create_or_fail_using (hb_blob_t *blob,
unsigned int index,
const char *loader_name);
HB_EXTERN hb_face_t *
hb_face_create_from_file_or_fail (const char *file_name,
unsigned int index);
HB_EXTERN hb_face_t *
hb_face_create_from_file_or_fail_using (const char *file_name,
unsigned int index,
const char *loader_name);
HB_EXTERN const char **
hb_face_list_loaders (void);
/**
* hb_reference_table_func_t:
* @face: an #hb_face_t to reference table for
@ -131,7 +117,7 @@ HB_EXTERN void
hb_face_make_immutable (hb_face_t *face);
HB_EXTERN hb_bool_t
hb_face_is_immutable (hb_face_t *face);
hb_face_is_immutable (const hb_face_t *face);
HB_EXTERN hb_blob_t *

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