diff --git a/libs/harfbuzz/.ci/build-win32.sh b/libs/harfbuzz/.ci/build-win32.sh index a1ca53d27..f97db2a1e 100644 --- a/libs/harfbuzz/.ci/build-win32.sh +++ b/libs/harfbuzz/.ci/build-win32.sh @@ -2,15 +2,17 @@ set -e meson --cross-file=.ci/win32-cross-file.txt \ - --wrap-mode=forcefallback \ + --wrap-mode=default \ -Dtests=disabled \ -Dcairo=enabled \ -Dcairo:fontconfig=disabled \ + -Dcairo:freetype=disabled \ + -Dcairo:dwrite=disabled \ + -Dcairo:tests=disabled \ -Dglib=enabled \ - -Dfreetype=enabled \ + -Dfreetype=disabled \ -Dgdi=enabled \ -Ddirectwrite=enabled \ - -Dcairo=enabled \ win32build \ $@ diff --git a/libs/harfbuzz/.ci/build-win64.sh b/libs/harfbuzz/.ci/build-win64.sh index 385d55974..b34ac0c19 100644 --- a/libs/harfbuzz/.ci/build-win64.sh +++ b/libs/harfbuzz/.ci/build-win64.sh @@ -2,15 +2,17 @@ set -e meson --cross-file=.ci/win64-cross-file.txt \ - --wrap-mode=forcefallback \ + --wrap-mode=default \ -Dtests=disabled \ -Dcairo=enabled \ -Dcairo:fontconfig=disabled \ + -Dcairo:freetype=disabled \ + -Dcairo:dwrite=disabled \ + -Dcairo:tests=disabled \ -Dglib=enabled \ - -Dfreetype=enabled \ + -Dfreetype=disabled \ -Dgdi=enabled \ -Ddirectwrite=enabled \ - -Dcairo=enabled \ win64build \ $@ diff --git a/libs/harfbuzz/.ci/requirements-fonttools.in b/libs/harfbuzz/.ci/requirements-fonttools.in new file mode 100644 index 000000000..d10c4b7e0 --- /dev/null +++ b/libs/harfbuzz/.ci/requirements-fonttools.in @@ -0,0 +1 @@ +fonttools \ No newline at end of file diff --git a/libs/harfbuzz/.ci/requirements-fonttools.txt b/libs/harfbuzz/.ci/requirements-fonttools.txt new file mode 100644 index 000000000..a020a2b6d --- /dev/null +++ b/libs/harfbuzz/.ci/requirements-fonttools.txt @@ -0,0 +1,56 @@ +# +# This file is autogenerated by pip-compile with Python 3.10 +# by the following command: +# +# pip-compile --generate-hashes .ci/requirements-fonttools.in +# +fonttools==4.54.1 \ + --hash=sha256:07e005dc454eee1cc60105d6a29593459a06321c21897f769a281ff2d08939f6 \ + --hash=sha256:0a911591200114969befa7f2cb74ac148bce5a91df5645443371aba6d222e263 \ + --hash=sha256:0d1d353ef198c422515a3e974a1e8d5b304cd54a4c2eebcae708e37cd9eeffb1 \ + --hash=sha256:0e88e3018ac809b9662615072dcd6b84dca4c2d991c6d66e1970a112503bba7e \ + --hash=sha256:1d152d1be65652fc65e695e5619e0aa0982295a95a9b29b52b85775243c06556 \ + --hash=sha256:262705b1663f18c04250bd1242b0515d3bbae177bee7752be67c979b7d47f43d \ + --hash=sha256:278913a168f90d53378c20c23b80f4e599dca62fbffae4cc620c8eed476b723e \ + --hash=sha256:301540e89cf4ce89d462eb23a89464fef50915255ece765d10eee8b2bf9d75b2 \ + --hash=sha256:31c32d7d4b0958600eac75eaf524b7b7cb68d3a8c196635252b7a2c30d80e986 \ + --hash=sha256:357cacb988a18aace66e5e55fe1247f2ee706e01debc4b1a20d77400354cddeb \ + --hash=sha256:37cddd62d83dc4f72f7c3f3c2bcf2697e89a30efb152079896544a93907733bd \ + --hash=sha256:41bb0b250c8132b2fcac148e2e9198e62ff06f3cc472065dff839327945c5882 \ + --hash=sha256:4aa4817f0031206e637d1e685251ac61be64d1adef111060df84fdcbc6ab6c44 \ + --hash=sha256:4e10d2e0a12e18f4e2dd031e1bf7c3d7017be5c8dbe524d07706179f355c5dac \ + --hash=sha256:5419771b64248484299fa77689d4f3aeed643ea6630b2ea750eeab219588ba20 \ + --hash=sha256:54471032f7cb5fca694b5f1a0aaeba4af6e10ae989df408e0216f7fd6cdc405d \ + --hash=sha256:58974b4987b2a71ee08ade1e7f47f410c367cdfc5a94fabd599c88165f56213a \ + --hash=sha256:58d29b9a294573d8319f16f2f79e42428ba9b6480442fa1836e4eb89c4d9d61c \ + --hash=sha256:5eb2474a7c5be8a5331146758debb2669bf5635c021aee00fd7c353558fc659d \ + --hash=sha256:6e37561751b017cf5c40fce0d90fd9e8274716de327ec4ffb0df957160be3bff \ + --hash=sha256:76ae5091547e74e7efecc3cbf8e75200bc92daaeb88e5433c5e3e95ea8ce5aa7 \ + --hash=sha256:7965af9b67dd546e52afcf2e38641b5be956d68c425bef2158e95af11d229f10 \ + --hash=sha256:7e3b7d44e18c085fd8c16dcc6f1ad6c61b71ff463636fcb13df7b1b818bd0c02 \ + --hash=sha256:7ed7ee041ff7b34cc62f07545e55e1468808691dddfd315d51dd82a6b37ddef2 \ + --hash=sha256:82834962b3d7c5ca98cb56001c33cf20eb110ecf442725dc5fdf36d16ed1ab07 \ + --hash=sha256:8583e563df41fdecef31b793b4dd3af8a9caa03397be648945ad32717a92885b \ + --hash=sha256:8fa92cb248e573daab8d032919623cc309c005086d743afb014c836636166f08 \ + --hash=sha256:93d458c8a6a354dc8b48fc78d66d2a8a90b941f7fec30e94c7ad9982b1fa6bab \ + --hash=sha256:957f669d4922f92c171ba01bef7f29410668db09f6c02111e22b2bce446f3285 \ + --hash=sha256:9dc080e5a1c3b2656caff2ac2633d009b3a9ff7b5e93d0452f40cd76d3da3b3c \ + --hash=sha256:9ef1b167e22709b46bf8168368b7b5d3efeaaa746c6d39661c1b4405b6352e58 \ + --hash=sha256:a7a310c6e0471602fe3bf8efaf193d396ea561486aeaa7adc1f132e02d30c4b9 \ + --hash=sha256:ab774fa225238986218a463f3fe151e04d8c25d7de09df7f0f5fce27b1243dbc \ + --hash=sha256:ada215fd079e23e060157aab12eba0d66704316547f334eee9ff26f8c0d7b8ab \ + --hash=sha256:c39287f5c8f4a0c5a55daf9eaf9ccd223ea59eed3f6d467133cc727d7b943a55 \ + --hash=sha256:c9c563351ddc230725c4bdf7d9e1e92cbe6ae8553942bd1fb2b2ff0884e8b714 \ + --hash=sha256:d26732ae002cc3d2ecab04897bb02ae3f11f06dd7575d1df46acd2f7c012a8d8 \ + --hash=sha256:d3b659d1029946f4ff9b6183984578041b520ce0f8fb7078bb37ec7445806b33 \ + --hash=sha256:dd9cc95b8d6e27d01e1e1f1fae8559ef3c02c76317da650a19047f249acd519d \ + --hash=sha256:e4564cf40cebcb53f3dc825e85910bf54835e8a8b6880d59e5159f0f325e637e \ + --hash=sha256:e7d82b9e56716ed32574ee106cabca80992e6bbdcf25a88d97d21f73a0aae664 \ + --hash=sha256:e8a4b261c1ef91e7188a30571be6ad98d1c6d9fa2427244c545e2fa0a2494dd7 \ + --hash=sha256:e96bc94c8cda58f577277d4a71f51c8e2129b8b36fd05adece6320dd3d57de8a \ + --hash=sha256:ed2f80ca07025551636c555dec2b755dd005e2ea8fbeb99fc5cdff319b70b23b \ + --hash=sha256:f5b8a096e649768c2f4233f947cf9737f8dbf8728b90e2771e2497c6e3d21d13 \ + --hash=sha256:f8e953cc0bddc2beaf3a3c3b5dd9ab7554677da72dfaf46951e193c9653e515a \ + --hash=sha256:fda582236fee135d4daeca056c8c88ec5f6f6d88a004a79b84a02547c8f57386 \ + --hash=sha256:fdb062893fd6d47b527d39346e0c5578b7957dcea6d6a3b6794569370013d9ac + # via -r requirements-fonttools.in diff --git a/libs/harfbuzz/.ci/requirements.in b/libs/harfbuzz/.ci/requirements.in new file mode 100644 index 000000000..ae131bdcf --- /dev/null +++ b/libs/harfbuzz/.ci/requirements.in @@ -0,0 +1,5 @@ +-r requirements-fonttools.in +meson==1.5.2 +gcovr==5.0 +ninja +setuptools # https://github.com/harfbuzz/harfbuzz/issues/4475 diff --git a/libs/harfbuzz/.ci/requirements.txt b/libs/harfbuzz/.ci/requirements.txt new file mode 100644 index 000000000..f30ff4f51 --- /dev/null +++ b/libs/harfbuzz/.ci/requirements.txt @@ -0,0 +1,251 @@ +# +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: +# +# pip-compile --allow-unsafe --generate-hashes --output-file=.ci/requirements.txt .ci/requirements.in +# +fonttools==4.54.1 \ + --hash=sha256:07e005dc454eee1cc60105d6a29593459a06321c21897f769a281ff2d08939f6 \ + --hash=sha256:0a911591200114969befa7f2cb74ac148bce5a91df5645443371aba6d222e263 \ + --hash=sha256:0d1d353ef198c422515a3e974a1e8d5b304cd54a4c2eebcae708e37cd9eeffb1 \ + --hash=sha256:0e88e3018ac809b9662615072dcd6b84dca4c2d991c6d66e1970a112503bba7e \ + --hash=sha256:1d152d1be65652fc65e695e5619e0aa0982295a95a9b29b52b85775243c06556 \ + --hash=sha256:262705b1663f18c04250bd1242b0515d3bbae177bee7752be67c979b7d47f43d \ + --hash=sha256:278913a168f90d53378c20c23b80f4e599dca62fbffae4cc620c8eed476b723e \ + --hash=sha256:301540e89cf4ce89d462eb23a89464fef50915255ece765d10eee8b2bf9d75b2 \ + --hash=sha256:31c32d7d4b0958600eac75eaf524b7b7cb68d3a8c196635252b7a2c30d80e986 \ + --hash=sha256:357cacb988a18aace66e5e55fe1247f2ee706e01debc4b1a20d77400354cddeb \ + --hash=sha256:37cddd62d83dc4f72f7c3f3c2bcf2697e89a30efb152079896544a93907733bd \ + --hash=sha256:41bb0b250c8132b2fcac148e2e9198e62ff06f3cc472065dff839327945c5882 \ + --hash=sha256:4aa4817f0031206e637d1e685251ac61be64d1adef111060df84fdcbc6ab6c44 \ + --hash=sha256:4e10d2e0a12e18f4e2dd031e1bf7c3d7017be5c8dbe524d07706179f355c5dac \ + --hash=sha256:5419771b64248484299fa77689d4f3aeed643ea6630b2ea750eeab219588ba20 \ + --hash=sha256:54471032f7cb5fca694b5f1a0aaeba4af6e10ae989df408e0216f7fd6cdc405d \ + --hash=sha256:58974b4987b2a71ee08ade1e7f47f410c367cdfc5a94fabd599c88165f56213a \ + --hash=sha256:58d29b9a294573d8319f16f2f79e42428ba9b6480442fa1836e4eb89c4d9d61c \ + --hash=sha256:5eb2474a7c5be8a5331146758debb2669bf5635c021aee00fd7c353558fc659d \ + --hash=sha256:6e37561751b017cf5c40fce0d90fd9e8274716de327ec4ffb0df957160be3bff \ + --hash=sha256:76ae5091547e74e7efecc3cbf8e75200bc92daaeb88e5433c5e3e95ea8ce5aa7 \ + --hash=sha256:7965af9b67dd546e52afcf2e38641b5be956d68c425bef2158e95af11d229f10 \ + --hash=sha256:7e3b7d44e18c085fd8c16dcc6f1ad6c61b71ff463636fcb13df7b1b818bd0c02 \ + --hash=sha256:7ed7ee041ff7b34cc62f07545e55e1468808691dddfd315d51dd82a6b37ddef2 \ + --hash=sha256:82834962b3d7c5ca98cb56001c33cf20eb110ecf442725dc5fdf36d16ed1ab07 \ + --hash=sha256:8583e563df41fdecef31b793b4dd3af8a9caa03397be648945ad32717a92885b \ + --hash=sha256:8fa92cb248e573daab8d032919623cc309c005086d743afb014c836636166f08 \ + --hash=sha256:93d458c8a6a354dc8b48fc78d66d2a8a90b941f7fec30e94c7ad9982b1fa6bab \ + --hash=sha256:957f669d4922f92c171ba01bef7f29410668db09f6c02111e22b2bce446f3285 \ + --hash=sha256:9dc080e5a1c3b2656caff2ac2633d009b3a9ff7b5e93d0452f40cd76d3da3b3c \ + --hash=sha256:9ef1b167e22709b46bf8168368b7b5d3efeaaa746c6d39661c1b4405b6352e58 \ + --hash=sha256:a7a310c6e0471602fe3bf8efaf193d396ea561486aeaa7adc1f132e02d30c4b9 \ + --hash=sha256:ab774fa225238986218a463f3fe151e04d8c25d7de09df7f0f5fce27b1243dbc \ + --hash=sha256:ada215fd079e23e060157aab12eba0d66704316547f334eee9ff26f8c0d7b8ab \ + --hash=sha256:c39287f5c8f4a0c5a55daf9eaf9ccd223ea59eed3f6d467133cc727d7b943a55 \ + --hash=sha256:c9c563351ddc230725c4bdf7d9e1e92cbe6ae8553942bd1fb2b2ff0884e8b714 \ + --hash=sha256:d26732ae002cc3d2ecab04897bb02ae3f11f06dd7575d1df46acd2f7c012a8d8 \ + --hash=sha256:d3b659d1029946f4ff9b6183984578041b520ce0f8fb7078bb37ec7445806b33 \ + --hash=sha256:dd9cc95b8d6e27d01e1e1f1fae8559ef3c02c76317da650a19047f249acd519d \ + --hash=sha256:e4564cf40cebcb53f3dc825e85910bf54835e8a8b6880d59e5159f0f325e637e \ + --hash=sha256:e7d82b9e56716ed32574ee106cabca80992e6bbdcf25a88d97d21f73a0aae664 \ + --hash=sha256:e8a4b261c1ef91e7188a30571be6ad98d1c6d9fa2427244c545e2fa0a2494dd7 \ + --hash=sha256:e96bc94c8cda58f577277d4a71f51c8e2129b8b36fd05adece6320dd3d57de8a \ + --hash=sha256:ed2f80ca07025551636c555dec2b755dd005e2ea8fbeb99fc5cdff319b70b23b \ + --hash=sha256:f5b8a096e649768c2f4233f947cf9737f8dbf8728b90e2771e2497c6e3d21d13 \ + --hash=sha256:f8e953cc0bddc2beaf3a3c3b5dd9ab7554677da72dfaf46951e193c9653e515a \ + --hash=sha256:fda582236fee135d4daeca056c8c88ec5f6f6d88a004a79b84a02547c8f57386 \ + --hash=sha256:fdb062893fd6d47b527d39346e0c5578b7957dcea6d6a3b6794569370013d9ac + # via -r requirements-fonttools.in +gcovr==5.0 \ + --hash=sha256:1d80264cbaadff356b3dda71b8c62b3aa803e5b3eb6d526a24932cd6660a2576 \ + --hash=sha256:8c49ebcfc5a98b56dd900c687aad0258ac86093d2f81a1417905193ab45fe69f + # via -r requirements.in +jinja2==3.1.4 \ + --hash=sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369 \ + --hash=sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d + # via gcovr +lxml==4.9.3 \ + --hash=sha256:05186a0f1346ae12553d66df1cfce6f251589fea3ad3da4f3ef4e34b2d58c6a3 \ + --hash=sha256:075b731ddd9e7f68ad24c635374211376aa05a281673ede86cbe1d1b3455279d \ + --hash=sha256:081d32421db5df44c41b7f08a334a090a545c54ba977e47fd7cc2deece78809a \ + --hash=sha256:0a3d3487f07c1d7f150894c238299934a2a074ef590b583103a45002035be120 \ + --hash=sha256:0bfd0767c5c1de2551a120673b72e5d4b628737cb05414f03c3277bf9bed3305 \ + --hash=sha256:0c0850c8b02c298d3c7006b23e98249515ac57430e16a166873fc47a5d549287 \ + --hash=sha256:0e2cb47860da1f7e9a5256254b74ae331687b9672dfa780eed355c4c9c3dbd23 \ + --hash=sha256:120fa9349a24c7043854c53cae8cec227e1f79195a7493e09e0c12e29f918e52 \ + --hash=sha256:1247694b26342a7bf47c02e513d32225ededd18045264d40758abeb3c838a51f \ + --hash=sha256:141f1d1a9b663c679dc524af3ea1773e618907e96075262726c7612c02b149a4 \ + --hash=sha256:14e019fd83b831b2e61baed40cab76222139926b1fb5ed0e79225bc0cae14584 \ + --hash=sha256:1509dd12b773c02acd154582088820893109f6ca27ef7291b003d0e81666109f \ + --hash=sha256:17a753023436a18e27dd7769e798ce302963c236bc4114ceee5b25c18c52c693 \ + --hash=sha256:1e224d5755dba2f4a9498e150c43792392ac9b5380aa1b845f98a1618c94eeef \ + --hash=sha256:1f447ea5429b54f9582d4b955f5f1985f278ce5cf169f72eea8afd9502973dd5 \ + --hash=sha256:23eed6d7b1a3336ad92d8e39d4bfe09073c31bfe502f20ca5116b2a334f8ec02 \ + --hash=sha256:25f32acefac14ef7bd53e4218fe93b804ef6f6b92ffdb4322bb6d49d94cad2bc \ + --hash=sha256:2c74524e179f2ad6d2a4f7caf70e2d96639c0954c943ad601a9e146c76408ed7 \ + --hash=sha256:303bf1edce6ced16bf67a18a1cf8339d0db79577eec5d9a6d4a80f0fb10aa2da \ + --hash=sha256:3331bece23c9ee066e0fb3f96c61322b9e0f54d775fccefff4c38ca488de283a \ + --hash=sha256:3e9bdd30efde2b9ccfa9cb5768ba04fe71b018a25ea093379c857c9dad262c40 \ + --hash=sha256:411007c0d88188d9f621b11d252cce90c4a2d1a49db6c068e3c16422f306eab8 \ + --hash=sha256:42871176e7896d5d45138f6d28751053c711ed4d48d8e30b498da155af39aebd \ + --hash=sha256:46f409a2d60f634fe550f7133ed30ad5321ae2e6630f13657fb9479506b00601 \ + --hash=sha256:48628bd53a426c9eb9bc066a923acaa0878d1e86129fd5359aee99285f4eed9c \ + --hash=sha256:48d6ed886b343d11493129e019da91d4039826794a3e3027321c56d9e71505be \ + --hash=sha256:4930be26af26ac545c3dffb662521d4e6268352866956672231887d18f0eaab2 \ + --hash=sha256:4aec80cde9197340bc353d2768e2a75f5f60bacda2bab72ab1dc499589b3878c \ + --hash=sha256:4c28a9144688aef80d6ea666c809b4b0e50010a2aca784c97f5e6bf143d9f129 \ + --hash=sha256:4d2d1edbca80b510443f51afd8496be95529db04a509bc8faee49c7b0fb6d2cc \ + --hash=sha256:4dd9a263e845a72eacb60d12401e37c616438ea2e5442885f65082c276dfb2b2 \ + --hash=sha256:4f1026bc732b6a7f96369f7bfe1a4f2290fb34dce00d8644bc3036fb351a4ca1 \ + --hash=sha256:4fb960a632a49f2f089d522f70496640fdf1218f1243889da3822e0a9f5f3ba7 \ + --hash=sha256:50670615eaf97227d5dc60de2dc99fb134a7130d310d783314e7724bf163f75d \ + --hash=sha256:50baa9c1c47efcaef189f31e3d00d697c6d4afda5c3cde0302d063492ff9b477 \ + --hash=sha256:53ace1c1fd5a74ef662f844a0413446c0629d151055340e9893da958a374f70d \ + --hash=sha256:5515edd2a6d1a5a70bfcdee23b42ec33425e405c5b351478ab7dc9347228f96e \ + --hash=sha256:56dc1f1ebccc656d1b3ed288f11e27172a01503fc016bcabdcbc0978b19352b7 \ + --hash=sha256:578695735c5a3f51569810dfebd05dd6f888147a34f0f98d4bb27e92b76e05c2 \ + --hash=sha256:57aba1bbdf450b726d58b2aea5fe47c7875f5afb2c4a23784ed78f19a0462574 \ + --hash=sha256:57d6ba0ca2b0c462f339640d22882acc711de224d769edf29962b09f77129cbf \ + --hash=sha256:5c245b783db29c4e4fbbbfc9c5a78be496c9fea25517f90606aa1f6b2b3d5f7b \ + --hash=sha256:5c31c7462abdf8f2ac0577d9f05279727e698f97ecbb02f17939ea99ae8daa98 \ + --hash=sha256:64f479d719dc9f4c813ad9bb6b28f8390360660b73b2e4beb4cb0ae7104f1c12 \ + --hash=sha256:65299ea57d82fb91c7f019300d24050c4ddeb7c5a190e076b5f48a2b43d19c42 \ + --hash=sha256:6689a3d7fd13dc687e9102a27e98ef33730ac4fe37795d5036d18b4d527abd35 \ + --hash=sha256:690dafd0b187ed38583a648076865d8c229661ed20e48f2335d68e2cf7dc829d \ + --hash=sha256:6fc3c450eaa0b56f815c7b62f2b7fba7266c4779adcf1cece9e6deb1de7305ce \ + --hash=sha256:704f61ba8c1283c71b16135caf697557f5ecf3e74d9e453233e4771d68a1f42d \ + --hash=sha256:71c52db65e4b56b8ddc5bb89fb2e66c558ed9d1a74a45ceb7dcb20c191c3df2f \ + --hash=sha256:71d66ee82e7417828af6ecd7db817913cb0cf9d4e61aa0ac1fde0583d84358db \ + --hash=sha256:7d298a1bd60c067ea75d9f684f5f3992c9d6766fadbc0bcedd39750bf344c2f4 \ + --hash=sha256:8b77946fd508cbf0fccd8e400a7f71d4ac0e1595812e66025bac475a8e811694 \ + --hash=sha256:8d7e43bd40f65f7d97ad8ef5c9b1778943d02f04febef12def25f7583d19baac \ + --hash=sha256:8df133a2ea5e74eef5e8fc6f19b9e085f758768a16e9877a60aec455ed2609b2 \ + --hash=sha256:8ed74706b26ad100433da4b9d807eae371efaa266ffc3e9191ea436087a9d6a7 \ + --hash=sha256:92af161ecbdb2883c4593d5ed4815ea71b31fafd7fd05789b23100d081ecac96 \ + --hash=sha256:97047f0d25cd4bcae81f9ec9dc290ca3e15927c192df17331b53bebe0e3ff96d \ + --hash=sha256:9719fe17307a9e814580af1f5c6e05ca593b12fb7e44fe62450a5384dbf61b4b \ + --hash=sha256:9767e79108424fb6c3edf8f81e6730666a50feb01a328f4a016464a5893f835a \ + --hash=sha256:9a92d3faef50658dd2c5470af249985782bf754c4e18e15afb67d3ab06233f13 \ + --hash=sha256:9bb6ad405121241e99a86efff22d3ef469024ce22875a7ae045896ad23ba2340 \ + --hash=sha256:9e28c51fa0ce5674be9f560c6761c1b441631901993f76700b1b30ca6c8378d6 \ + --hash=sha256:aca086dc5f9ef98c512bac8efea4483eb84abbf926eaeedf7b91479feb092458 \ + --hash=sha256:ae8b9c6deb1e634ba4f1930eb67ef6e6bf6a44b6eb5ad605642b2d6d5ed9ce3c \ + --hash=sha256:b0a545b46b526d418eb91754565ba5b63b1c0b12f9bd2f808c852d9b4b2f9b5c \ + --hash=sha256:b4e4bc18382088514ebde9328da057775055940a1f2e18f6ad2d78aa0f3ec5b9 \ + --hash=sha256:b6420a005548ad52154c8ceab4a1290ff78d757f9e5cbc68f8c77089acd3c432 \ + --hash=sha256:b86164d2cff4d3aaa1f04a14685cbc072efd0b4f99ca5708b2ad1b9b5988a991 \ + --hash=sha256:bb3bb49c7a6ad9d981d734ef7c7193bc349ac338776a0360cc671eaee89bcf69 \ + --hash=sha256:bef4e656f7d98aaa3486d2627e7d2df1157d7e88e7efd43a65aa5dd4714916cf \ + --hash=sha256:c0781a98ff5e6586926293e59480b64ddd46282953203c76ae15dbbbf302e8bb \ + --hash=sha256:c2006f5c8d28dee289f7020f721354362fa304acbaaf9745751ac4006650254b \ + --hash=sha256:c41bfca0bd3532d53d16fd34d20806d5c2b1ace22a2f2e4c0008570bf2c58833 \ + --hash=sha256:cd47b4a0d41d2afa3e58e5bf1f62069255aa2fd6ff5ee41604418ca925911d76 \ + --hash=sha256:cdb650fc86227eba20de1a29d4b2c1bfe139dc75a0669270033cb2ea3d391b85 \ + --hash=sha256:cef2502e7e8a96fe5ad686d60b49e1ab03e438bd9123987994528febd569868e \ + --hash=sha256:d27be7405547d1f958b60837dc4c1007da90b8b23f54ba1f8b728c78fdb19d50 \ + --hash=sha256:d37017287a7adb6ab77e1c5bee9bcf9660f90ff445042b790402a654d2ad81d8 \ + --hash=sha256:d3ff32724f98fbbbfa9f49d82852b159e9784d6094983d9a8b7f2ddaebb063d4 \ + --hash=sha256:d73d8ecf8ecf10a3bd007f2192725a34bd62898e8da27eb9d32a58084f93962b \ + --hash=sha256:dd708cf4ee4408cf46a48b108fb9427bfa00b9b85812a9262b5c668af2533ea5 \ + --hash=sha256:e3cd95e10c2610c360154afdc2f1480aea394f4a4f1ea0a5eacce49640c9b190 \ + --hash=sha256:e4da8ca0c0c0aea88fd46be8e44bd49716772358d648cce45fe387f7b92374a7 \ + --hash=sha256:eadfbbbfb41b44034a4c757fd5d70baccd43296fb894dba0295606a7cf3124aa \ + --hash=sha256:ed667f49b11360951e201453fc3967344d0d0263aa415e1619e85ae7fd17b4e0 \ + --hash=sha256:f3df3db1d336b9356dd3112eae5f5c2b8b377f3bc826848567f10bfddfee77e9 \ + --hash=sha256:f6bdac493b949141b733c5345b6ba8f87a226029cbabc7e9e121a413e49441e0 \ + --hash=sha256:fbf521479bcac1e25a663df882c46a641a9bff6b56dc8b0fafaebd2f66fb231b \ + --hash=sha256:fc9b106a1bf918db68619fdcd6d5ad4f972fdd19c01d19bdb6bf63f3589a9ec5 \ + --hash=sha256:fcdd00edfd0a3001e0181eab3e63bd5c74ad3e67152c84f93f13769a40e073a7 \ + --hash=sha256:fe4bda6bd4340caa6e5cf95e73f8fea5c4bfc55763dd42f1b50a94c1b4a2fbd4 + # via gcovr +markupsafe==2.1.3 \ + --hash=sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e \ + --hash=sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e \ + --hash=sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431 \ + --hash=sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686 \ + --hash=sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c \ + --hash=sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559 \ + --hash=sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc \ + --hash=sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb \ + --hash=sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939 \ + --hash=sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c \ + --hash=sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0 \ + --hash=sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4 \ + --hash=sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9 \ + --hash=sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575 \ + --hash=sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba \ + --hash=sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d \ + --hash=sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd \ + --hash=sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3 \ + --hash=sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00 \ + --hash=sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155 \ + --hash=sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac \ + --hash=sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52 \ + --hash=sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f \ + --hash=sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8 \ + --hash=sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b \ + --hash=sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007 \ + --hash=sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24 \ + --hash=sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea \ + --hash=sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198 \ + --hash=sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0 \ + --hash=sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee \ + --hash=sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be \ + --hash=sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2 \ + --hash=sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1 \ + --hash=sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707 \ + --hash=sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6 \ + --hash=sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c \ + --hash=sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58 \ + --hash=sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823 \ + --hash=sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779 \ + --hash=sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636 \ + --hash=sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c \ + --hash=sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad \ + --hash=sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee \ + --hash=sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc \ + --hash=sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2 \ + --hash=sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48 \ + --hash=sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7 \ + --hash=sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e \ + --hash=sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b \ + --hash=sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa \ + --hash=sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5 \ + --hash=sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e \ + --hash=sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb \ + --hash=sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9 \ + --hash=sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57 \ + --hash=sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc \ + --hash=sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc \ + --hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2 \ + --hash=sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11 + # via jinja2 +meson==1.5.2 \ + --hash=sha256:77706e2368a00d789c097632ccf4fc39251fba56d03e1e1b262559a3c7a08f5b \ + --hash=sha256:f955e09ab0d71ef180ae85df65991d58ed8430323de7d77a37e11c9ea630910b + # via -r requirements.in +ninja==1.11.1.1 \ + --hash=sha256:18302d96a5467ea98b68e1cae1ae4b4fb2b2a56a82b955193c637557c7273dbd \ + --hash=sha256:185e0641bde601e53841525c4196278e9aaf4463758da6dd1e752c0a0f54136a \ + --hash=sha256:376889c76d87b95b5719fdd61dd7db193aa7fd4432e5d52d2e44e4c497bdbbee \ + --hash=sha256:3e0f9be5bb20d74d58c66cc1c414c3e6aeb45c35b0d0e41e8d739c2c0d57784f \ + --hash=sha256:73b93c14046447c7c5cc892433d4fae65d6364bec6685411cb97a8bcf815f93a \ + --hash=sha256:7563ce1d9fe6ed5af0b8dd9ab4a214bf4ff1f2f6fd6dc29f480981f0f8b8b249 \ + --hash=sha256:76482ba746a2618eecf89d5253c0d1e4f1da1270d41e9f54dfbd91831b0f6885 \ + --hash=sha256:84502ec98f02a037a169c4b0d5d86075eaf6afc55e1879003d6cab51ced2ea4b \ + --hash=sha256:95da904130bfa02ea74ff9c0116b4ad266174fafb1c707aa50212bc7859aebf1 \ + --hash=sha256:9d793b08dd857e38d0b6ffe9e6b7145d7c485a42dcfea04905ca0cdb6017cc3c \ + --hash=sha256:9df724344202b83018abb45cb1efc22efd337a1496514e7e6b3b59655be85205 \ + --hash=sha256:aad34a70ef15b12519946c5633344bc775a7656d789d9ed5fdb0d456383716ef \ + --hash=sha256:d491fc8d89cdcb416107c349ad1e3a735d4c4af5e1cb8f5f727baca6350fdaea \ + --hash=sha256:ecf80cf5afd09f14dcceff28cb3f11dc90fb97c999c89307aea435889cb66877 \ + --hash=sha256:fa2ba9d74acfdfbfbcf06fad1b8282de8a7a8c481d9dee45c859a8c93fcc1082 + # via -r requirements.in +pygments==2.16.1 \ + --hash=sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692 \ + --hash=sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29 + # via gcovr + +# The following packages are considered to be unsafe in a requirements file: +setuptools==73.0.1 \ + --hash=sha256:b208925fcb9f7af924ed2dc04708ea89791e24bde0d3020b27df0e116088b34e \ + --hash=sha256:d59a3e788ab7e012ab2c4baed1b376da6366883ee20d7a5fc426816e3d7b1193 + # via -r requirements.in diff --git a/libs/harfbuzz/.circleci/config.yml b/libs/harfbuzz/.circleci/config.yml index 9525c4aec..45f440ffa 100644 --- a/libs/harfbuzz/.circleci/config.yml +++ b/libs/harfbuzz/.circleci/config.yml @@ -3,53 +3,50 @@ version: 2.1 executors: win32-executor: docker: - - image: cimg/base:edge-20.04 + - image: cimg/base:2023.10 win64-executor: docker: - - image: cimg/base:edge-20.04 - autotools-executor: + - image: cimg/base:2023.10 + dist-executor: docker: - - image: cimg/base:edge-20.04 + - image: cimg/base:2023.10 jobs: macos-aat-fonts: macos: - xcode: "12.5.1" + xcode: "15.3.0" steps: - checkout - - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install pkg-config ragel freetype glib cairo python3 icu4c graphite2 gobject-introspection gtk-doc ninja + - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install pkg-config ragel freetype glib cairo python3 icu4c graphite2 gobject-introspection ninja - run: pip3 install meson --upgrade - - run: PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:/usr/local/opt/libffi/lib/pkgconfig" meson build -Dcoretext=enabled -Dgraphite=enabled -Dauto_features=enabled -Dchafa=disabled + - run: brew link --force icu4c + - run: PKG_CONFIG_PATH="/usr/local/opt/libffi/lib/pkgconfig" meson setup build -Dcoretext=enabled -Dgraphite=enabled -Dauto_features=enabled -Dchafa=disabled -Ddocs=disabled - run: meson compile -Cbuild - run: meson test -Cbuild --print-errorlogs - store_artifacts: path: build/meson-logs/ - # will be dropped with autotools removal - distcheck: - executor: autotools-executor + dist: + executor: dist-executor steps: - checkout - - run: sudo apt update && DEBIAN_FRONTEND=noninteractive sudo apt install -y git ninja-build binutils libtool autoconf automake make gcc g++ pkg-config ragel gtk-doc-tools gobject-introspection libfreetype6-dev libglib2.0-dev libgirepository1.0-dev libcairo2-dev libicu-dev libgraphite2-dev python3 python3-pip + - run: sudo apt update && DEBIAN_FRONTEND=noninteractive sudo apt install -y git ninja-build binutils gcc g++ pkg-config ragel gtk-doc-tools gobject-introspection libfreetype6-dev libglib2.0-dev libgirepository1.0-dev libcairo2-dev libicu-dev libgraphite2-dev python3 python3-pip - run: pip3 install fonttools meson --upgrade - - run: ./autogen.sh - - run: make -j2 distcheck - - run: rm harfbuzz-* && make distdir - - run: cd harfbuzz-* && meson build && ninja -j2 -Cbuild test - - run: make dist + - run: meson setup build + - run: meson dist --no-tests -Cbuild - persist_to_workspace: root: . - paths: harfbuzz-*.tar.xz + paths: build/meson-dist/harfbuzz-*.tar.xz publish-dist: - executor: autotools-executor + executor: dist-executor steps: - checkout - attach_workspace: at: . - run: | - .ci/publish_release_artifact.sh harfbuzz-$CIRCLE_TAG.tar.xz + .ci/publish_release_artifact.sh build/meson-dist/harfbuzz-$CIRCLE_TAG.tar.xz fedora-valgrind: docker: @@ -57,8 +54,8 @@ jobs: steps: - checkout - run: dnf install -y pkg-config ragel valgrind gcc gcc-c++ meson git glib2-devel freetype-devel cairo-devel libicu-devel gobject-introspection-devel graphite2-devel redhat-rpm-config python python-pip || true - - run: meson build --buildtype=debugoptimized - - run: ninja -Cbuild -j9 + - run: meson setup build --buildtype=debugoptimized + - run: meson compile -Cbuild -j9 # TOOD: increase timeouts and remove --no-suite=slow - run: RUN_VALGRIND=1 meson test -Cbuild --no-suite=slow --wrap='valgrind --leak-check=full --error-exitcode=1' --print-errorlogs --num-processes=$(($(nproc)/2 + 1)) @@ -68,36 +65,28 @@ jobs: steps: - checkout - run: apk update && apk add ragel gcc g++ glib-dev freetype-dev cairo-dev git py3-pip ninja - - run: pip3 install meson==0.56.0 - - run: meson build --buildtype=minsize - - run: ninja -Cbuild -j9 - - run: meson test -Cbuild --print-errorlogs - - archlinux: - docker: - - image: archlinux/base - steps: - - checkout - - run: pacman --noconfirm -Syu freetype2 meson git clang cairo icu gettext gobject-introspection gcc gcc-libs glib2 graphite pkg-config ragel python python-pip base-devel gtk-doc - - run: pip install flake8 fonttools - - run: flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics - - run: meson build -Dgraphite=enabled -Dauto_features=enabled -Dexperimental_api=true - - run: meson compile -Cbuild -j9 - - run: meson test -Cbuild --print-errorlogs - - run: meson dist -Cbuild - - run: clang -c src/harfbuzz.cc -DHB_NO_MT - - run: clang -c src/hb-*.cc -DHB_NO_MT -DHB_TINY -DHB_NO_OT_FONT + - 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:20.04 + - image: ubuntu steps: - checkout - run: apt update || true - - run: DEBIAN_FRONTEND=noninteractive apt install -y python3 python3-pip ninja-build clang lld git binutils pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev - - run: pip3 install meson==0.56.0 - - run: CC=clang CXX=clang++ meson build --default-library=static -Db_sanitize=address,undefined --buildtype=debugoptimized --wrap-mode=nodownload -Dexperimental_api=true - - run: ninja -Cbuild -j8 && meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt + - 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: | + python3 -m venv venv + source venv/bin/activate + 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 --print-errorlogs | asan_symbolize | c++filt tsan: docker: @@ -105,10 +94,14 @@ jobs: steps: - checkout - run: apt update || true - - run: DEBIAN_FRONTEND=noninteractive apt install -y python3 python3-pip ninja-build clang lld git binutils pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev - - run: pip3 install meson==0.56.0 - - run: CC=clang CXX=clang++ meson build --default-library=static -Db_sanitize=thread --buildtype=debugoptimized --wrap-mode=nodownload -Dexperimental_api=true - - run: ninja -Cbuild -j8 && meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt + - 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: | + python3 -m venv venv + source venv/bin/activate + 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 --print-errorlogs | asan_symbolize | c++filt msan: docker: @@ -116,15 +109,19 @@ jobs: steps: - checkout - run: apt update || true - - run: DEBIAN_FRONTEND=noninteractive apt install -y python3 python3-pip ninja-build clang lld git binutils pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev - - run: pip3 install meson==0.56.0 - # msan, needs --force-fallback-for=glib,freetype2 also which doesn't work yet but runs fuzzer cases at least - - run: CC=clang CXX=clang++ meson build --default-library=static -Db_sanitize=memory --buildtype=debugoptimized --wrap-mode=nodownload -Dauto_features=disabled -Dtests=enabled -Dexperimental_api=true - - run: ninja -Cbuild -j8 && meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt + - 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: | + python3 -m venv venv + source venv/bin/activate + pip3 install meson==0.56.0 + # msan, needs --force-fallback-for=glib,freetype2 also which doesn't work yet but runs fuzzer cases at least + CC=clang CXX=clang++ meson setup build --default-library=static -Db_sanitize=memory --buildtype=debugoptimized --wrap-mode=nodownload -Dauto_features=disabled -Dtests=enabled -Dexperimental_api=true + meson compile -Cbuild -j9 + meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt clang-cxx2a: docker: - - image: ubuntu:20.04 + - image: ubuntu steps: - checkout - run: apt update || true @@ -135,9 +132,12 @@ jobs: executor: win32-executor steps: - checkout - - run: sudo apt update && DEBIAN_FRONTEND=noninteractive sudo apt install -y ninja-build gtk-doc-tools python3 python3-pip git g++-mingw-w64-i686 zip - - run: pip3 install meson==0.56.0 --upgrade - - run: .ci/build-win32.sh + - 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: | + python3 -m venv venv + source venv/bin/activate + pip3 install meson==0.60.0 + bash .ci/build-win32.sh - store_artifacts: path: harfbuzz-win32.zip - persist_to_workspace: @@ -158,9 +158,12 @@ jobs: executor: win64-executor steps: - checkout - - run: sudo apt update && DEBIAN_FRONTEND=noninteractive sudo apt install -y ninja-build gtk-doc-tools python3 python3-pip git g++-mingw-w64-x86-64 zip - - run: pip3 install meson==0.56.0 --upgrade - - run: bash .ci/build-win64.sh + - 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: | + python3 -m venv venv + source venv/bin/activate + pip3 install meson==0.60.0 + bash .ci/build-win64.sh - store_artifacts: path: harfbuzz-win64.zip - persist_to_workspace: @@ -184,13 +187,13 @@ workflows: build: jobs: - macos-aat-fonts - - distcheck: + - dist: filters: # must have filter or won't work as a dependency tags: only: /.*/ - publish-dist: requires: - - distcheck + - dist filters: tags: only: /^\d+\.\d+\.\d+$/ @@ -198,7 +201,6 @@ workflows: ignore: /.*/ - fedora-valgrind - alpine - #- archlinux - asan-ubsan - tsan - msan diff --git a/libs/harfbuzz/.codecov.yml b/libs/harfbuzz/.codecov.yml index abd04ca9f..40928b932 100644 --- a/libs/harfbuzz/.codecov.yml +++ b/libs/harfbuzz/.codecov.yml @@ -1,8 +1,10 @@ -comment: off +comment: false coverage: status: project: default: - threshold: 1% - patch: off + informational: true + patch: + default: + informational: true diff --git a/libs/harfbuzz/.editorconfig b/libs/harfbuzz/.editorconfig index cac917b91..cc612b9ba 100644 --- a/libs/harfbuzz/.editorconfig +++ b/libs/harfbuzz/.editorconfig @@ -9,14 +9,11 @@ insert_final_newline = true [*.{c,cc,h,hh,rl}] tab_width = 8 indent_size = 2 -indent_style = tab # should be space +indent_style = tab [*.{py,sh}] indent_style = tab -[{Makefile.am,Makefile.sources,configure.ac}] -tab_width = 8 - [{meson.build,meson_options.txt}] tab_width = 8 indent_style = space diff --git a/libs/harfbuzz/.github/dependabot.yml b/libs/harfbuzz/.github/dependabot.yml index 5ace4600a..8725672a1 100644 --- a/libs/harfbuzz/.github/dependabot.yml +++ b/libs/harfbuzz/.github/dependabot.yml @@ -4,3 +4,7 @@ updates: directory: "/" schedule: interval: "weekly" + - package-ecosystem: "pip" + directory: "/.ci" + schedule: + interval: "weekly" diff --git a/libs/harfbuzz/.github/workflows/arm-ci.yml b/libs/harfbuzz/.github/workflows/arm-ci.yml new file mode 100644 index 000000000..498e182e1 --- /dev/null +++ b/libs/harfbuzz/.github/workflows/arm-ci.yml @@ -0,0 +1,25 @@ +name: arm + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +permissions: + contents: read + +jobs: + arm-none-eabi: + runs-on: ubuntu-22.04 + container: + image: devkitpro/devkitarm:latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: Configure CMake + run: | + cmake -S . -B build \ + -DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/3DS.cmake + - name: Build + run: make CXX_FLAGS="-w -DHB_NO_MT" + working-directory: build diff --git a/libs/harfbuzz/.github/workflows/cifuzz.yml b/libs/harfbuzz/.github/workflows/cifuzz.yml index 07e4cd575..8c0d5816c 100644 --- a/libs/harfbuzz/.github/workflows/cifuzz.yml +++ b/libs/harfbuzz/.github/workflows/cifuzz.yml @@ -1,5 +1,9 @@ name: CIFuzz on: [pull_request] + +permissions: + contents: read + jobs: Fuzzing: runs-on: ubuntu-latest @@ -17,7 +21,7 @@ jobs: fuzz-seconds: 600 dry-run: false - name: Upload Crash - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 if: failure() && steps.build.outcome == 'success' with: name: artifacts diff --git a/libs/harfbuzz/.github/workflows/configs-build.yml b/libs/harfbuzz/.github/workflows/configs-build.yml index 9f4fd78e6..1c9bea353 100644 --- a/libs/harfbuzz/.github/workflows/configs-build.yml +++ b/libs/harfbuzz/.github/workflows/configs-build.yml @@ -11,10 +11,10 @@ permissions: jobs: build: - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: install dependencies run: sudo apt-get install gcc - name: HB_DISABLE_DEPRECATED diff --git a/libs/harfbuzz/.github/workflows/coverity-scan.yml b/libs/harfbuzz/.github/workflows/coverity-scan.yml index e9fc5435e..502b6208f 100644 --- a/libs/harfbuzz/.github/workflows/coverity-scan.yml +++ b/libs/harfbuzz/.github/workflows/coverity-scan.yml @@ -11,7 +11,7 @@ jobs: latest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - run: sudo apt-get install gcc clang wget git curl pkg-config libfreetype6-dev libglib2.0-dev libicu-dev libgraphite2-dev diff --git a/libs/harfbuzz/.github/workflows/linux-ci.yml b/libs/harfbuzz/.github/workflows/linux-ci.yml index f67f5d3fe..5bb640445 100644 --- a/libs/harfbuzz/.github/workflows/linux-ci.yml +++ b/libs/harfbuzz/.github/workflows/linux-ci.yml @@ -12,46 +12,65 @@ permissions: jobs: build: - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3 - - name: install dependencies - run: sudo apt-get update && sudo apt-get install pkg-config gcc gtk-doc-tools libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python3 python3-setuptools ninja-build gobject-introspection libgirepository1.0-dev - - run: sudo pip3 install fonttools meson==0.56.0 gcovr==5.0 - - name: run - run: meson build -Db_coverage=true --auto-features=enabled -Dgraphite=enabled -Dchafa=disabled -Dragel_subproject=true -Doptimization=2 - - name: ci + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: Setup Ccache + uses: hendrikmuhs/ccache-action@ed74d11c0b343532753ecead8a951bb09bb34bc9 # v1.2.14 + with: + key: ${{ github.job }}-${{ runner.os }}-${{ runner.arch }} + - name: Install Dependencies + run: | + sudo apt-get update + sudo apt-get install \ + gcc \ + gobject-introspection \ + gtk-doc-tools \ + libcairo2-dev \ + libfreetype6-dev \ + libgirepository1.0-dev \ + libglib2.0-dev \ + libgraphite2-dev \ + libicu-dev \ + ninja-build \ + pkg-config \ + python3 \ + python3-setuptools + - name: Setup Python + uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + with: + python-version: '3.x' + - name: Install Python Dependencies + run: sudo 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 \ + -Db_coverage=true \ + -Ddoc_tests=true \ + -Dragel_subproject=true + - name: Build + run: meson compile -Cbuild + - name: Test run: meson test --print-errorlogs -Cbuild - - - name: generate documentations + - name: Generate Documentations run: ninja -Cbuild harfbuzz-doc - - name: deploy documentations + - name: Deploy Documentations if: github.ref_type == 'tag' run: .ci/deploy-docs.sh env: GH_TOKEN: ${{ secrets.GH_TOKEN }} REVISION: ${{ github.sha }} - - # waiting for https://github.com/rhysd/github-action-benchmark/issues/36 to happen - # - name: benchmark - # run: build/perf/perf --benchmark_format=json > perf/result.json - # - name: store benchmark result - # uses: rhysd/github-action-benchmark@b2ee598 - # if: github.event_name != 'pull_request' - # with: - # name: C++ Benchmark - # tool: 'googlecpp' - # output-file-path: perf/result.json - # gh-pages-branch: gh-pages - # github-token: ${{ secrets.PERSONAL_GITHUB_TOKEN }} - # auto-push: true - # alert-threshold: '150%' - # comment-on-alert: true - # fail-on-alert: true - - - name: cov + - name: Generate Coverage run: ninja -Cbuild coverage-xml - - uses: codecov/codecov-action@v3 + - name: Upload Coverage + uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4.6.0 with: + token: ${{ secrets.CODECOV_TOKEN }} file: build/meson-logs/coverage.xml diff --git a/libs/harfbuzz/.github/workflows/macos-ci.yml b/libs/harfbuzz/.github/workflows/macos-ci.yml index a6b6d3dbf..42617a1f1 100644 --- a/libs/harfbuzz/.github/workflows/macos-ci.yml +++ b/libs/harfbuzz/.github/workflows/macos-ci.yml @@ -14,17 +14,54 @@ jobs: runs-on: macos-latest steps: - - uses: actions/checkout@v3 - - name: install dependencies - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install pkg-config freetype glib glib-utils cairo icu4c graphite2 gobject-introspection gtk-doc ninja - - run: pip3 install fonttools meson==0.56.0 gcovr==5.0 - - name: run - run: PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:/usr/local/opt/libffi/lib/pkgconfig" meson build -Db_coverage=true -Dcoretext=enabled -Dgraphite=enabled -Dauto_features=enabled -Dchafa=disabled -Doptimization=2 - - name: ci + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: Setup Ccache + uses: hendrikmuhs/ccache-action@ed74d11c0b343532753ecead8a951bb09bb34bc9 # v1.2.14 + with: + key: ${{ github.job }}-${{ runner.os }}-${{ runner.arch }} + - name: Install Dependencies + run: | + export HOMEBREW_NO_AUTO_UPDATE=1 + export HOMEBREW_NO_INSTALL_CLEANUP=1 + brew install \ + cairo \ + freetype \ + glib \ + gobject-introspection \ + graphite2 \ + icu4c \ + meson \ + ninja \ + pkg-config + - name: Setup Python + uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + with: + python-version: '3.12' + - name: Install Python Dependencies + run: pip3 install -r .ci/requirements.txt --require-hashes + - name: Setup Meson + env: + PKG_CONFIG_PATH: "/usr/local/opt/libffi/lib/pkgconfig" + run: | + brew link --force icu4c + ccache --version + meson setup build \ + -Dauto_features=enabled \ + -Ddocs=disabled \ + -Dchafa=disabled \ + -Dcoretext=enabled \ + -Dgraphite=enabled \ + -Doptimization=2 \ + -Db_coverage=true \ + - name: Build + run: meson compile -Cbuild + - name: Test run: meson test --print-errorlogs -Cbuild - - - name: cov + - name: Generate Coverage run: ninja -Cbuild coverage-xml - - uses: codecov/codecov-action@v3 + - name: Upload Coverage + uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4.6.0 with: + token: ${{ secrets.CODECOV_TOKEN }} file: build/meson-logs/coverage.xml diff --git a/libs/harfbuzz/.github/workflows/msvc-ci.yml b/libs/harfbuzz/.github/workflows/msvc-ci.yml index 57aef04cb..6226b5b07 100644 --- a/libs/harfbuzz/.github/workflows/msvc-ci.yml +++ b/libs/harfbuzz/.github/workflows/msvc-ci.yml @@ -14,6 +14,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: os: [windows-2019, windows-latest] include: @@ -26,33 +27,35 @@ jobs: name: ${{ matrix.name }} steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 - with: - python-version: '3.x' - - uses: ilammy/msvc-dev-cmd@v1 - with: - arch : ${{ matrix.ARCH }} - - name: Upgrade pip - run: | - python -m pip install -U pip - - name: Install Dependencies - run: | - pip install --upgrade meson ninja fonttools - - name: Build - run: | - # This dir contains a pkg-config which meson will happily use and later fail, so remove it - $env:path = ($env:path.Split(';') | Where-Object { $_ -ne 'C:\Strawberry\perl\bin' }) -join ';' - + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: Setup Ccache + uses: hendrikmuhs/ccache-action@ed74d11c0b343532753ecead8a951bb09bb34bc9 # v1.2.14 + with: + variant: sccache + key: ${{ github.job }}-${{ matrix.os }}-${{ matrix.ARCH }} + - name: Setup Python + uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + with: + python-version: '3.x' + - name: Setup MSVC + uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0 + with: + arch : ${{ matrix.ARCH }} + - name: Install Python Dependencies + run: | + pip3 install -r .ci/requirements.txt --require-hashes + - name: Setup Meson + run: | + sccache --version meson setup build ` - --wrap-mode=default ` + --wrap-mode=forcefallback ` --buildtype=release ` -Dglib=enabled ` -Dfreetype=enabled ` -Dgdi=enabled ` -Ddirectwrite=enabled - - meson compile -C build - - name: Test - run: | - meson test --print-errorlogs --suite=harfbuzz -C build + - name: Build + run: meson compile -Cbuild + - name: Test + run: meson test --print-errorlogs --suite=harfbuzz -Cbuild diff --git a/libs/harfbuzz/.github/workflows/msys2-ci.yml b/libs/harfbuzz/.github/workflows/msys2-ci.yml index 0704f4caf..ad55b4fe3 100644 --- a/libs/harfbuzz/.github/workflows/msys2-ci.yml +++ b/libs/harfbuzz/.github/workflows/msys2-ci.yml @@ -14,6 +14,7 @@ jobs: runs-on: windows-latest strategy: + fail-fast: false matrix: include: - MSYSTEM: MINGW32 @@ -22,47 +23,60 @@ jobs: MSYS2_ARCH: x86_64 name: ${{ matrix.MSYSTEM }} + env: + # XXX: For some reason enabling jit debugging "fixes" random python crashes + # see https://github.com/msys2/MINGW-packages/issues/11864 + MSYS: "winjitdebug" + defaults: run: shell: msys2 {0} steps: - - uses: actions/checkout@v3 - - uses: msys2/setup-msys2@v2 - with: - msystem: ${{ matrix.MSYSTEM }} - update: true - install: >- - mingw-w64-${{ matrix.MSYS2_ARCH }}-cairo - mingw-w64-${{ matrix.MSYS2_ARCH }}-freetype - mingw-w64-${{ matrix.MSYS2_ARCH }}-gcc - mingw-w64-${{ matrix.MSYS2_ARCH }}-gcc-libs - mingw-w64-${{ matrix.MSYS2_ARCH }}-gettext - mingw-w64-${{ matrix.MSYS2_ARCH }}-glib2 - mingw-w64-${{ matrix.MSYS2_ARCH }}-gobject-introspection - mingw-w64-${{ matrix.MSYS2_ARCH }}-graphite2 - mingw-w64-${{ matrix.MSYS2_ARCH }}-icu - mingw-w64-${{ matrix.MSYS2_ARCH }}-meson - mingw-w64-${{ matrix.MSYS2_ARCH }}-ninja - mingw-w64-${{ matrix.MSYS2_ARCH }}-pkg-config - mingw-w64-${{ matrix.MSYS2_ARCH }}-python - mingw-w64-${{ matrix.MSYS2_ARCH }}-python-pip - mingw-w64-${{ matrix.MSYS2_ARCH }}-ragel - - name: Install Python Dependencies - run: | - pip install --upgrade fonttools - - name: Build - run: | - meson build \ - --wrap-mode=nodownload \ - --auto-features=enabled \ - -Ddirectwrite=enabled \ - -Dgdi=enabled \ - -Dgraphite=enabled \ - -Dchafa=disabled - ninja -C build - - name: Test - run: | - meson test \ - --print-errorlogs \ - --suite=harfbuzz \ - -C build + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: Setup MSYS2 + uses: msys2/setup-msys2@cf96e00c0aab3788743aaf63b64146f0d383cee9 # v2 + with: + msystem: ${{ matrix.MSYSTEM }} + update: true + install: >- + mingw-w64-${{ matrix.MSYS2_ARCH }}-cairo + mingw-w64-${{ matrix.MSYS2_ARCH }}-freetype + mingw-w64-${{ matrix.MSYS2_ARCH }}-gcc + mingw-w64-${{ matrix.MSYS2_ARCH }}-gcc-libs + mingw-w64-${{ matrix.MSYS2_ARCH }}-gettext + mingw-w64-${{ matrix.MSYS2_ARCH }}-glib2 + mingw-w64-${{ matrix.MSYS2_ARCH }}-gobject-introspection + mingw-w64-${{ matrix.MSYS2_ARCH }}-graphite2 + mingw-w64-${{ matrix.MSYS2_ARCH }}-icu + mingw-w64-${{ matrix.MSYS2_ARCH }}-meson + mingw-w64-${{ matrix.MSYS2_ARCH }}-ninja + mingw-w64-${{ matrix.MSYS2_ARCH }}-pkg-config + mingw-w64-${{ matrix.MSYS2_ARCH }}-python + mingw-w64-${{ matrix.MSYS2_ARCH }}-python-pip + - name: 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 + - name: Setup Meson + run: | + meson setup build \ + --wrap-mode=nodownload \ + --auto-features=enabled \ + -Ddocs=disabled \ + -Ddirectwrite=enabled \ + -Dgdi=enabled \ + -Dgraphite=enabled \ + -Dchafa=disabled + - name: Build + run: meson compile -Cbuild + - name: Test + run: meson test --print-errorlogs --suite=harfbuzz -Cbuild + - name: Upload DLLs + if: always() + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 + with: + name: libharfbuzz-${{ matrix.MSYS2_ARCH }} + path: ./build/src/libharfbuzz-*.dll diff --git a/libs/harfbuzz/.github/workflows/scorecard.yml b/libs/harfbuzz/.github/workflows/scorecard.yml new file mode 100644 index 000000000..5e80cd34d --- /dev/null +++ b/libs/harfbuzz/.github/workflows/scorecard.yml @@ -0,0 +1,64 @@ +# This workflow uses actions that are not certified by GitHub. They are provided +# by a third-party and are governed by separate terms of service, privacy +# policy, and support documentation. + +name: Scorecard supply-chain security +on: + # For Branch-Protection check. Only the default branch is supported. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection + branch_protection_rule: + # To guarantee Maintained check is occasionally updated. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained + schedule: + - cron: '19 14 * * 6' + push: + branches: [ "main" ] + +# Declare default permissions as read only. +permissions: read-all + +jobs: + analysis: + name: Scorecard analysis + runs-on: ubuntu-latest + permissions: + # Needed to upload the results to code-scanning dashboard. + security-events: write + # Needed to publish results and get a badge (see publish_results below). + id-token: write + + steps: + - name: "Checkout code" + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + + - name: "Run analysis" + uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0 + with: + results_file: results.sarif + results_format: sarif + # (Optional) Fine-grained PAT token. Uncomment the `repo_token` line below if: + # you want to enable the full Branch-Protection check on a *public* repository + # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-fine-grained-pat-optional. + # repo_token: ${{ secrets.SCORECARD_TOKEN }} + + # - Publish results to OpenSSF REST API for easy access by consumers + # - Allows the repository to include the Scorecard badge. + # - See https://github.com/ossf/scorecard-action#publishing-results. + publish_results: true + + # 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@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 + with: + name: SARIF file + path: results.sarif + retention-days: 5 + + # Upload the results to GitHub's code scanning dashboard. + - name: "Upload to code-scanning" + uses: github/codeql-action/upload-sarif@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0 + with: + sarif_file: results.sarif diff --git a/libs/harfbuzz/BUILD.md b/libs/harfbuzz/BUILD.md index 8e822738c..e0dd17b83 100644 --- a/libs/harfbuzz/BUILD.md +++ b/libs/harfbuzz/BUILD.md @@ -1,20 +1,23 @@ On Linux, install the development packages for FreeType, Cairo, and GLib. For example, on Ubuntu / Debian, you would do: -$ sudo apt-get install meson pkg-config ragel gtk-doc-tools gcc g++ libfreetype6-dev libglib2.0-dev libcairo2-dev + $ sudo apt-get install meson pkg-config ragel gtk-doc-tools gcc g++ libfreetype6-dev libglib2.0-dev libcairo2-dev whereas on Fedora, RHEL, CentOS, and other Red Hat based systems you would do: -$ sudo dnf install meson pkgconfig gtk-doc gcc gcc-c++ freetype-devel glib2-devel cairo-devel + $ sudo dnf install meson pkgconfig gtk-doc gcc gcc-c++ freetype-devel glib2-devel cairo-devel and on ArchLinux and Manjaro: -$ sudo pacman -Suy meson pkg-config ragel gcc freetype2 glib2 cairo + $ sudo pacman -Suy meson pkg-config ragel gcc freetype2 glib2 glib2-devel cairo -then use meson to build the project like `meson build && meson test -Cbuild`. +On macOS: -On macOS, `brew install pkg-config ragel gtk-doc freetype glib cairo meson` -then use meson like above. + brew install pkg-config ragel gtk-doc freetype glib cairo meson + +Then use meson to build the project and run the tests, like: + + meson build && ninja -Cbuild && meson test -Cbuild On Windows, meson can build the project like above if a working MSVC's cl.exe (`vcvarsall.bat`) or gcc/clang is already on your path, and if you use @@ -22,8 +25,8 @@ something like `meson build --wrap-mode=default` it fetches and compiles most of the dependencies also. It is recommended to install CMake either manually or via the Visual Studio installer when building with MSVC, using meson. -Our CI configurations is also a good source of learning how to build HarfBuzz. +Our CI configurations are also a good source of learning how to build HarfBuzz. -There is also amalgam source provided with HarfBuzz which reduces whole process -of building HarfBuzz like `g++ src/harfbuzz.cc -fno-exceptions` but there is -not guarantee provided with buildability and reliability of features you get. +There is also amalgamated source provided with HarfBuzz which reduces whole process +of building HarfBuzz to `g++ src/harfbuzz.cc -fno-exceptions` but there is +no guarantee provided with buildability and reliability of features you get. diff --git a/libs/harfbuzz/CMakeLists.txt b/libs/harfbuzz/CMakeLists.txt index 59464c475..3f6bba09d 100644 --- a/libs/harfbuzz/CMakeLists.txt +++ b/libs/harfbuzz/CMakeLists.txt @@ -3,6 +3,9 @@ project(harfbuzz) message(WARN "HarfBuzz has a Meson port and tries to migrate all the other build systems to it, please consider using it as we might remove our cmake port soon.") +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + ## Limit framework build to Xcode generator if (BUILD_FRAMEWORK) # for a framework build on macOS, use: @@ -33,6 +36,7 @@ endif () ## HarfBuzz build configurations +option(HB_HAVE_CAIRO "Enable cairo interop helpers" OFF) option(HB_HAVE_FREETYPE "Enable freetype interop helpers" OFF) option(HB_HAVE_GRAPHITE2 "Enable Graphite2 complementary shaper" OFF) option(HB_HAVE_GLIB "Enable glib unicode functions" OFF) @@ -74,8 +78,8 @@ include_directories(AFTER ${PROJECT_BINARY_DIR}/src ) -# We need PYTHON_EXECUTABLE to be set for running the tests... -include (FindPythonInterp) +# We need Python3_EXECUTABLE to be set for running the tests... +find_package(Python3 COMPONENTS Interpreter) ## Functions and headers include (CheckFunctionExists) @@ -123,6 +127,7 @@ endif () if (MSVC) add_definitions(-wd4244 -wd4267 -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS) + add_definitions(-bigobj) endif () @@ -133,54 +138,8 @@ endif () # #set (HB_VERSION_H "${PROJECT_SOURCE_DIR}/src/hb-version.h") # endif () - -## Extract variables from Makefile files -function (extract_make_variable variable makefile_source) - string(REGEX MATCH "${variable} = ([^$]+)\\$" temp "${makefile_source}") - string(REGEX MATCHALL "[^ \n\t\\]+" listVar "${CMAKE_MATCH_1}") - set (${variable} ${listVar} PARENT_SCOPE) -endfunction () - -# https://stackoverflow.com/a/27630120 -function (add_prefix_to_list var prefix) - set (listVar "") - foreach (f ${${var}}) - list(APPEND listVar "${prefix}${f}") - endforeach () - set (${var} "${listVar}" PARENT_SCOPE) -endfunction () - -file(READ ${PROJECT_SOURCE_DIR}/src/Makefile.sources SRCSOURCES) -file(READ ${PROJECT_SOURCE_DIR}/util/Makefile.sources UTILSOURCES) - -extract_make_variable(HB_BASE_headers ${SRCSOURCES}) -add_prefix_to_list(HB_BASE_headers "${PROJECT_SOURCE_DIR}/src/") - -extract_make_variable(HB_SUBSET_sources ${SRCSOURCES}) -add_prefix_to_list(HB_SUBSET_sources "${PROJECT_SOURCE_DIR}/src/") - -extract_make_variable(HB_SUBSET_headers ${SRCSOURCES}) -add_prefix_to_list(HB_SUBSET_headers "${PROJECT_SOURCE_DIR}/src/") - -extract_make_variable(HB_BASE_RAGEL_GENERATED_sources ${SRCSOURCES}) -#if (IN_HB_DIST) - add_prefix_to_list(HB_BASE_RAGEL_GENERATED_sources "${PROJECT_SOURCE_DIR}/src/") -#else () -# add_prefix_to_list(HB_BASE_RAGEL_GENERATED_sources "${PROJECT_BINARY_DIR}/src/") -#endif () - -extract_make_variable(HB_VIEW_sources ${UTILSOURCES}) -add_prefix_to_list(HB_VIEW_sources "${PROJECT_SOURCE_DIR}/util/") -extract_make_variable(HB_SHAPE_sources ${UTILSOURCES}) -add_prefix_to_list(HB_SHAPE_sources "${PROJECT_SOURCE_DIR}/util/") -extract_make_variable(HB_SUBSET_CLI_sources ${UTILSOURCES}) -add_prefix_to_list(HB_SUBSET_CLI_sources "${PROJECT_SOURCE_DIR}/util/") -extract_make_variable(HB_OT_SHAPE_CLOSURE_sources ${UTILSOURCES}) -add_prefix_to_list(HB_OT_SHAPE_CLOSURE_sources "${PROJECT_SOURCE_DIR}/util/") - - -file(READ configure.ac CONFIGUREAC) -string(REGEX MATCH "\\[(([0-9]+)\\.([0-9]+)\\.([0-9]+))\\]" HB_VERSION_MATCH ${CONFIGUREAC}) +file(READ meson.build MESONBUILD) +string(REGEX MATCH "version: '(([0-9]+)\\.([0-9]+)\\.([0-9]+))'," HB_VERSION_MATCH ${MESONBUILD}) set (HB_VERSION ${CMAKE_MATCH_1}) set (HB_VERSION_MAJOR ${CMAKE_MATCH_2}) set (HB_VERSION_MINOR ${CMAKE_MATCH_3}) @@ -188,10 +147,80 @@ set (HB_VERSION_MICRO ${CMAKE_MATCH_4}) ## Define sources and headers of the project set (project_sources ${PROJECT_SOURCE_DIR}/src/harfbuzz.cc) # use amalgam source -set (subset_project_sources ${HB_SUBSET_sources}) +set (subset_project_sources + ${PROJECT_SOURCE_DIR}/src/hb-number.cc + ${PROJECT_SOURCE_DIR}/src/hb-number.hh + ${PROJECT_SOURCE_DIR}/src/hb-ot-cff1-table.cc + ${PROJECT_SOURCE_DIR}/src/hb-ot-cff2-table.cc + ${PROJECT_SOURCE_DIR}/src/hb-ot-post-table-v2subset.hh + ${PROJECT_SOURCE_DIR}/src/hb-static.cc + ${PROJECT_SOURCE_DIR}/src/hb-subset-cff-common.cc + ${PROJECT_SOURCE_DIR}/src/hb-subset-cff-common.hh + ${PROJECT_SOURCE_DIR}/src/hb-subset-cff1.cc + ${PROJECT_SOURCE_DIR}/src/hb-subset-cff2.cc + ${PROJECT_SOURCE_DIR}/src/hb-subset-input.cc + ${PROJECT_SOURCE_DIR}/src/hb-subset-input.hh + ${PROJECT_SOURCE_DIR}/src/hb-subset-instancer-iup.hh + ${PROJECT_SOURCE_DIR}/src/hb-subset-instancer-iup.cc + ${PROJECT_SOURCE_DIR}/src/hb-subset-instancer-solver.hh + ${PROJECT_SOURCE_DIR}/src/hb-subset-instancer-solver.cc + ${PROJECT_SOURCE_DIR}/src/hb-subset-accelerator.hh + ${PROJECT_SOURCE_DIR}/src/hb-subset-plan.cc + ${PROJECT_SOURCE_DIR}/src/hb-subset-plan.hh + ${PROJECT_SOURCE_DIR}/src/hb-subset-plan-member-list.hh + ${PROJECT_SOURCE_DIR}/src/hb-subset-repacker.cc + ${PROJECT_SOURCE_DIR}/src/hb-subset.cc + ${PROJECT_SOURCE_DIR}/src/hb-subset.hh + ${PROJECT_SOURCE_DIR}/src/hb-repacker.hh + ${PROJECT_SOURCE_DIR}/src/graph/graph.hh + ${PROJECT_SOURCE_DIR}/src/graph/gsubgpos-graph.hh + ${PROJECT_SOURCE_DIR}/src/graph/gsubgpos-context.hh + ${PROJECT_SOURCE_DIR}/src/graph/gsubgpos-context.cc + ${PROJECT_SOURCE_DIR}/src/graph/coverage-graph.hh + ${PROJECT_SOURCE_DIR}/src/graph/classdef-graph.hh + ${PROJECT_SOURCE_DIR}/src/graph/pairpos-graph.hh + ${PROJECT_SOURCE_DIR}/src/graph/markbasepos-graph.hh + ${PROJECT_SOURCE_DIR}/src/graph/split-helpers.hh + ${PROJECT_SOURCE_DIR}/src/graph/serialize.hh + ${PROJECT_SOURCE_DIR}/src/OT/Color/COLR/colrv1-closure.hh +) set (project_extra_sources) -set (project_headers ${HB_BASE_headers}) -set (subset_project_headers ${HB_SUBSET_headers}) +set (project_headers + ${PROJECT_SOURCE_DIR}/src/hb-aat-layout.h + ${PROJECT_SOURCE_DIR}/src/hb-aat.h + ${PROJECT_SOURCE_DIR}/src/hb-blob.h + ${PROJECT_SOURCE_DIR}/src/hb-buffer.h + ${PROJECT_SOURCE_DIR}/src/hb-common.h + ${PROJECT_SOURCE_DIR}/src/hb-cplusplus.hh + ${PROJECT_SOURCE_DIR}/src/hb-deprecated.h + ${PROJECT_SOURCE_DIR}/src/hb-draw.h + ${PROJECT_SOURCE_DIR}/src/hb-face.h + ${PROJECT_SOURCE_DIR}/src/hb-font.h + ${PROJECT_SOURCE_DIR}/src/hb-map.h + ${PROJECT_SOURCE_DIR}/src/hb-ot-color.h + ${PROJECT_SOURCE_DIR}/src/hb-ot-deprecated.h + ${PROJECT_SOURCE_DIR}/src/hb-ot-font.h + ${PROJECT_SOURCE_DIR}/src/hb-ot-layout.h + ${PROJECT_SOURCE_DIR}/src/hb-ot-math.h + ${PROJECT_SOURCE_DIR}/src/hb-ot-meta.h + ${PROJECT_SOURCE_DIR}/src/hb-ot-metrics.h + ${PROJECT_SOURCE_DIR}/src/hb-ot-name.h + ${PROJECT_SOURCE_DIR}/src/hb-ot-shape.h + ${PROJECT_SOURCE_DIR}/src/hb-ot-var.h + ${PROJECT_SOURCE_DIR}/src/hb-ot.h + ${PROJECT_SOURCE_DIR}/src/hb-paint.h + ${PROJECT_SOURCE_DIR}/src/hb-set.h + ${PROJECT_SOURCE_DIR}/src/hb-shape-plan.h + ${PROJECT_SOURCE_DIR}/src/hb-shape.h + ${PROJECT_SOURCE_DIR}/src/hb-style.h + ${PROJECT_SOURCE_DIR}/src/hb-unicode.h + ${PROJECT_SOURCE_DIR}/src/hb-version.h + ${PROJECT_SOURCE_DIR}/src/hb.h +) +set (subset_project_headers + ${PROJECT_SOURCE_DIR}/src/hb-subset.h + ${PROJECT_SOURCE_DIR}/src/hb-subset-repacker.h +) ## Find and include needed header folders and libraries if (HB_HAVE_FREETYPE AND NOT TARGET freetype) @@ -259,20 +288,15 @@ endif () if (HB_HAVE_ICU) add_definitions(-DHAVE_ICU) - # https://github.com/WebKit/webkit/blob/fdd7733f2f30eab7fe096a9791f98c60f62f49c0/Source/cmake/FindICU.cmake - find_package(PkgConfig) - pkg_check_modules(PC_ICU QUIET icu-uc) - - find_path(ICU_INCLUDE_DIR NAMES unicode/utypes.h HINTS ${PC_ICU_INCLUDE_DIRS} ${PC_ICU_INCLUDEDIR}) - find_library(ICU_LIBRARY NAMES libicuuc cygicuuc cygicuuc32 icuuc HINTS ${PC_ICU_LIBRARY_DIRS} ${PC_ICU_LIBDIR}) + find_package(ICU REQUIRED COMPONENTS uc) - include_directories(${ICU_INCLUDE_DIR}) + if (ICU_VERSION VERSION_GREATER_EQUAL 75.1) + set(CMAKE_CXX_STANDARD 17) + endif () list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-icu.h) - list(APPEND THIRD_PARTY_LIBS ${ICU_LIBRARY}) - - mark_as_advanced(ICU_INCLUDE_DIR ICU_LIBRARY) + list(APPEND THIRD_PARTY_LIBS ICU::uc) endif () if (APPLE AND HB_HAVE_CORETEXT) @@ -340,6 +364,23 @@ if (WIN32 AND HB_HAVE_DIRECTWRITE) list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-directwrite.h) endif () +if (HB_HAVE_CAIRO) + # https://github.com/WebKit/webkit/blob/master/Source/cmake/FindCairo.cmake + find_package(PkgConfig) + pkg_check_modules(PC_CAIRO QUIET cairo) + + find_path(CAIRO_INCLUDE_DIRS NAMES cairo.h HINTS ${PC_CAIRO_INCLUDEDIR} ${PC_CAIRO_INCLUDE_DIRS} PATH_SUFFIXES cairo) + find_library(CAIRO_LIBRARIESNAMES cairo HINTS ${PC_CAIRO_LIBDIR} ${PC_CAIRO_LIBRARY_DIRS}) + if (NOT CAIRO_LIBRARIESNAMES) + message(FATAL_ERROR "HB_HAVE_CAIRO is ON but Cairo libraries are not found") + endif() + include_directories(${CAIRO_INCLUDE_DIRS}) + mark_as_advanced(CAIRO_INCLUDE_DIRS CAIRO_LIBRARIESNAMES) + add_definitions(-DHAVE_CAIRO=1) + list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-cairo.h) + list(APPEND THIRD_PARTY_LIBS ${CAIRO_LIBRARIESNAMES}) +endif() + if (HB_HAVE_GOBJECT) add_definitions(-DHAVE_GOBJECT) include (FindPerl) @@ -357,13 +398,13 @@ if (HB_HAVE_GOBJECT) # in the standard cmd.exe shell that we use, so we need to # first determine whether glib-mkenums is a Python or PERL # script - execute_process(COMMAND "${PYTHON_EXECUTABLE}" "${GLIB_MKENUMS}" --version + execute_process(COMMAND "${Python3_EXECUTABLE}" "${GLIB_MKENUMS}" --version RESULT_VARIABLE GLIB_MKENUMS_PYTHON OUTPUT_QUIET ERROR_QUIET ) if (GLIB_MKENUMS_PYTHON EQUAL 0) message("${GLIB_MKENUMS} is a Python script.") - set (GLIB_MKENUMS_CMD "${PYTHON_EXECUTABLE}" "${GLIB_MKENUMS}") + set (GLIB_MKENUMS_CMD "${Python3_EXECUTABLE}" "${GLIB_MKENUMS}") else () execute_process(COMMAND "${PERL_EXECUTABLE}" "${GLIB_MKENUMS}" --version RESULT_VARIABLE GLIB_MKENUMS_PERL @@ -472,7 +513,7 @@ endif () ## Define harfbuzz-subset library if (HB_BUILD_SUBSET) add_library(harfbuzz-subset ${subset_project_sources} ${subset_project_headers}) - list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-subset.h) + list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-subset.h ${PROJECT_SOURCE_DIR}/src/hb-subset-repacker.h) add_dependencies(harfbuzz-subset harfbuzz) target_link_libraries(harfbuzz-subset harfbuzz ${THIRD_PARTY_LIBS}) @@ -481,7 +522,7 @@ if (HB_BUILD_SUBSET) endif () endif () -if (UNIX OR MINGW) +if (UNIX OR MINGW OR VITA) # Make symbols link locally include (CheckCXXCompilerFlag) CHECK_CXX_COMPILER_FLAG(-Bsymbolic-functions CXX_SUPPORTS_FLAG_BSYMB_FUNCS) @@ -531,6 +572,18 @@ if (HB_HAVE_GOBJECT) endif () endif () +## Define harfbuzz-cairo library +if (HB_HAVE_CAIRO) + include_directories(${CAIRO_INCLUDE_DIRS}) + add_library(harfbuzz-cairo ${PROJECT_SOURCE_DIR}/src/hb-cairo.cc ${PROJECT_SOURCE_DIR}/src/hb-static.cc ${PROJECT_SOURCE_DIR}/src/hb-cairo.h) + add_dependencies(harfbuzz-cairo harfbuzz) + target_link_libraries(harfbuzz-cairo harfbuzz ${THIRD_PARTY_LIBS}) + + if (BUILD_SHARED_LIBS) + set_target_properties(harfbuzz-cairo PROPERTIES VISIBILITY_INLINES_HIDDEN TRUE) + endif () +endif() + if (BUILD_SHARED_LIBS AND WIN32 AND NOT MINGW) add_definitions("-DHB_DLL_EXPORT") endif () @@ -557,8 +610,8 @@ if (HB_HAVE_INTROSPECTION) if (WIN32 AND NOT MINGW) # Note that since we already enable HB_HAVE_GOBJECT - # we would already have PYTHON_EXECUTABLE handy - set (G_IR_SCANNER_CMD "${PYTHON_EXECUTABLE}" "${G_IR_SCANNER}") + # we would already have Python3_EXECUTABLE handy + set (G_IR_SCANNER_CMD "${Python3_EXECUTABLE}" "${G_IR_SCANNER}") else () set (G_IR_SCANNER_CMD "${G_IR_SCANNER}") endif () @@ -566,7 +619,7 @@ if (HB_HAVE_INTROSPECTION) # We need to account for the varying output directories # when we build using Visual Studio projects if ("${CMAKE_GENERATOR}" MATCHES "Visual Studio*") - set (hb_libpath "${CMAKE_CURRENT_BINARY_DIR}/$") + set (hb_libpath "${CMAKE_CURRENT_BINARY_DIR}/$") else () set (hb_libpath "$") endif () @@ -635,14 +688,8 @@ if (HB_HAVE_INTROSPECTION) -I${PROJECT_BINARY_DIR}/src ${hb_includedir_cflags} ${hb_defines_cflags} - -DHB_H - -DHB_H_IN - -DHB_OT_H - -DHB_OT_H_IN - -DHB_AAT_H - -DHB_AAT_H_IN - -DHB_GOBJECT_H - -DHB_GOBJECT_H_IN + -DHB_NO_SINGLE_HEADER_ERROR + -DHB_HAVE_GOBJECT -DHB_EXTERN= --cflags-end --library=harfbuzz-gobject @@ -683,30 +730,78 @@ endif () ## Additional harfbuzz build artifacts if (HB_BUILD_UTILS) - # https://github.com/WebKit/webkit/blob/master/Source/cmake/FindCairo.cmake - find_package(PkgConfig) - pkg_check_modules(PC_CAIRO QUIET cairo) - - find_path(CAIRO_INCLUDE_DIRS NAMES cairo.h HINTS ${PC_CAIRO_INCLUDEDIR} ${PC_CAIRO_INCLUDE_DIRS} PATH_SUFFIXES cairo) - find_library(CAIRO_LIBRARIESNAMES cairo HINTS ${PC_CAIRO_LIBDIR} ${PC_CAIRO_LIBRARY_DIRS}) - add_definitions("-DPACKAGE_NAME=\"HarfBuzz\"") add_definitions("-DPACKAGE_VERSION=\"${HB_VERSION}\"") - include_directories(${CAIRO_INCLUDE_DIRS}) - add_executable(hb-view ${HB_VIEW_sources}) - target_link_libraries(hb-view harfbuzz ${CAIRO_LIBRARIESNAMES}) + if (HB_HAVE_CAIRO) + add_executable(hb-view + ${PROJECT_SOURCE_DIR}/util/ansi-print.hh + ${PROJECT_SOURCE_DIR}/util/face-options.hh + ${PROJECT_SOURCE_DIR}/util/font-options.hh + ${PROJECT_SOURCE_DIR}/util/hb-view.cc + ${PROJECT_SOURCE_DIR}/util/helper-cairo-ansi.hh + ${PROJECT_SOURCE_DIR}/util/helper-cairo-ft.hh + ${PROJECT_SOURCE_DIR}/util/helper-cairo.hh + ${PROJECT_SOURCE_DIR}/util/main-font-text.hh + ${PROJECT_SOURCE_DIR}/util/options.hh + ${PROJECT_SOURCE_DIR}/util/output-options.hh + ${PROJECT_SOURCE_DIR}/util/shape-consumer.hh + ${PROJECT_SOURCE_DIR}/util/shape-options.hh + ${PROJECT_SOURCE_DIR}/util/text-options.hh + ${PROJECT_SOURCE_DIR}/util/view-cairo.hh + ${PROJECT_SOURCE_DIR}/util/view-options.hh + ) + target_link_libraries(hb-view harfbuzz-cairo harfbuzz ${CAIRO_LIBRARIESNAMES}) + endif() - add_executable(hb-shape ${HB_SHAPE_sources}) + add_executable(hb-shape + ${PROJECT_SOURCE_DIR}/util/batch.hh + ${PROJECT_SOURCE_DIR}/util/face-options.hh + ${PROJECT_SOURCE_DIR}/util/font-options.hh + ${PROJECT_SOURCE_DIR}/util/hb-shape.cc + ${PROJECT_SOURCE_DIR}/util/main-font-text.hh + ${PROJECT_SOURCE_DIR}/util/options.hh + ${PROJECT_SOURCE_DIR}/util/output-options.hh + ${PROJECT_SOURCE_DIR}/util/shape-consumer.hh + ${PROJECT_SOURCE_DIR}/util/shape-format.hh + ${PROJECT_SOURCE_DIR}/util/shape-options.hh + ${PROJECT_SOURCE_DIR}/util/shape-output.hh + ${PROJECT_SOURCE_DIR}/util/text-options.hh + ) target_link_libraries(hb-shape harfbuzz) - add_executable(hb-subset ${HB_SUBSET_CLI_sources}) + add_executable(hb-subset + ${PROJECT_SOURCE_DIR}/util/batch.hh + ${PROJECT_SOURCE_DIR}/util/face-options.hh + ${PROJECT_SOURCE_DIR}/util/hb-subset.cc + ${PROJECT_SOURCE_DIR}/util/main-font-text.hh + ${PROJECT_SOURCE_DIR}/util/options.hh + ${PROJECT_SOURCE_DIR}/util/output-options.hh + ${PROJECT_SOURCE_DIR}/util/text-options.hh + ${PROJECT_SOURCE_DIR}/util/helper-subset.hh + ) target_link_libraries(hb-subset harfbuzz harfbuzz-subset) - add_executable(hb-ot-shape-closure ${HB_OT_SHAPE_CLOSURE_sources}) + add_executable(hb-ot-shape-closure + ${PROJECT_SOURCE_DIR}/util/face-options.hh + ${PROJECT_SOURCE_DIR}/util/font-options.hh + ${PROJECT_SOURCE_DIR}/util/hb-ot-shape-closure.cc + ${PROJECT_SOURCE_DIR}/util/main-font-text.hh + ${PROJECT_SOURCE_DIR}/util/options.hh + ${PROJECT_SOURCE_DIR}/util/text-options.hh + ) target_link_libraries(hb-ot-shape-closure harfbuzz) - mark_as_advanced(CAIRO_INCLUDE_DIRS CAIRO_LIBRARIESNAMES) + if (HB_HAVE_GOBJECT) + add_executable(hb-info + ${PROJECT_SOURCE_DIR}/util/batch.hh + ${PROJECT_SOURCE_DIR}/util/face-options.hh + ${PROJECT_SOURCE_DIR}/util/font-options.hh + ${PROJECT_SOURCE_DIR}/util/hb-info.cc + ${PROJECT_SOURCE_DIR}/util/options.hh + ) + target_link_libraries(hb-info harfbuzz-gobject harfbuzz) + endif() endif () if (MEGA) @@ -746,7 +841,7 @@ macro ( make_pkgconfig_pc_file name ) string(REPLACE "%libdir%" "${CMAKE_INSTALL_LIBDIR}" FSTR ${FSTR}) else () string(REPLACE "%libdir%" "\${prefix}/${CMAKE_INSTALL_LIBDIR}" FSTR ${FSTR}) - endif () + endif () string(REPLACE "%VERSION%" "${HB_VERSION}" FSTR ${FSTR}) string(REPLACE "%requires_private%" "${PC_REQUIRES_PRIV}" FSTR ${FSTR}) @@ -761,6 +856,28 @@ macro ( make_pkgconfig_pc_file name ) ) endmacro ( make_pkgconfig_pc_file ) +# Generate hb-features.h with the features we enabled +macro (make_hb_features_h) + file(READ "${PROJECT_SOURCE_DIR}/src/hb-features.h.in" feature_h_in) + foreach(arg cairo coretext directwrite freetype gdi glib gobject graphite icu uniscribe wasm) + string(TOUPPER ${arg} feature_caps) + set(feature_instring "#mesondefine HB_HAS_${feature_caps}") + if (HB_HAVE_${feature_caps}) + set(feature_outstring "#define HB_HAS_${feature_caps} 1") + else () + set(feature_outstring "/* #undef HB_HAS_${feature_caps} */") + endif() + string(REPLACE ${feature_instring} ${feature_outstring} feature_h_in ${feature_h_in}) + endforeach() + file(WRITE "${PROJECT_BINARY_DIR}/src/hb-features.h" ${feature_h_in}) + if (NOT SKIP_INSTALL_HEADERS AND NOT SKIP_INSTALL_ALL) + install( + FILES "${PROJECT_BINARY_DIR}/src/hb-features.h" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/harfbuzz" + ) + endif() +endmacro (make_hb_features_h) + if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL) install(TARGETS harfbuzz EXPORT harfbuzzConfig @@ -783,6 +900,15 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL) ) make_pkgconfig_pc_file("harfbuzz-icu") endif () + if (HB_HAVE_CAIRO) + install(TARGETS harfbuzz-cairo + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + FRAMEWORK DESTINATION Library/Frameworks + ) + make_pkgconfig_pc_file("harfbuzz-cairo") + endif () if (HB_BUILD_SUBSET) install(TARGETS harfbuzz-subset ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} @@ -795,9 +921,11 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL) RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) endif () - install(TARGETS hb-view - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - ) + if (HB_HAVE_CAIRO) + install(TARGETS hb-view + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ) + endif() install(TARGETS hb-subset RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) @@ -806,6 +934,12 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL) RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) + if (HB_HAVE_GOBJECT) + install(TARGETS hb-info + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ) + endif() + install(TARGETS hb-ot-shape-closure RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) @@ -819,7 +953,7 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL) make_pkgconfig_pc_file("harfbuzz-gobject") if (HB_HAVE_INTROSPECTION) if ("${CMAKE_GENERATOR}" MATCHES "Visual Studio*") - set (hb_libpath "${CMAKE_CURRENT_BINARY_DIR}/$") + set (hb_libpath "${CMAKE_CURRENT_BINARY_DIR}/$") else () set (hb_libpath "$") endif () @@ -833,4 +967,5 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL) ) endif () endif () + make_hb_features_h() endif () diff --git a/libs/harfbuzz/CONFIG.md b/libs/harfbuzz/CONFIG.md index 0faa359e6..b054bf6de 100644 --- a/libs/harfbuzz/CONFIG.md +++ b/libs/harfbuzz/CONFIG.md @@ -130,6 +130,10 @@ The pre-defined configurations are: disabling thread-safety and debugging, and use even more size-optimized data tables. +To setup the build with these options use something like: +``` +$ meson setup build -Dcpp_args=-DHB_MINI -Dc_args=-DHB_MINI +``` ## Tailoring configuration @@ -144,7 +148,7 @@ the macro `HB_CONFIG_OVERRIDE_H` to the string containing to that header file's name. HarfBuzz will then include that file at the appropriate place during configuration. -Up until HarfBuzz 3.1.2 the the configuration override header file's name was +Up until HarfBuzz 3.1.2, the configuration override header file's name was fixed and called `config-override.h`, and was activated by defining the macro `HAVE_CONFIG_OVERRIDE_H`. That still works. @@ -155,4 +159,4 @@ Note that the config option `HB_NO_CFF`, which is enabled by `HB_LEAN` and `HB_TINY` does *not* mean that the resulting library won't work with CFF fonts. The library can shape valid CFF fonts just fine, with or without this option. This option disables (among other things) the code to calculate glyph extents -for CFF fonts, which many clients might not need. +for CFF fonts or draw them, which many clients might not need. diff --git a/libs/harfbuzz/COPYING b/libs/harfbuzz/COPYING index 48d1b30f9..1dd917e9f 100644 --- a/libs/harfbuzz/COPYING +++ b/libs/harfbuzz/COPYING @@ -2,19 +2,23 @@ HarfBuzz is licensed under the so-called "Old MIT" license. Details follow. For parts of HarfBuzz that are licensed under different licenses see individual files names COPYING in subdirectories where applicable. -Copyright © 2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020 Google, Inc. -Copyright © 2018,2019,2020 Ebrahim Byagowi +Copyright © 2010-2022 Google, Inc. +Copyright © 2015-2020 Ebrahim Byagowi Copyright © 2019,2020 Facebook, Inc. -Copyright © 2012 Mozilla Foundation +Copyright © 2012,2015 Mozilla Foundation Copyright © 2011 Codethink Limited Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies) Copyright © 2009 Keith Stribley -Copyright © 2009 Martin Hosken and SIL International +Copyright © 2011 Martin Hosken and SIL International Copyright © 2007 Chris Wilson -Copyright © 2005,2006,2020,2021 Behdad Esfahbod -Copyright © 2005 David Turner -Copyright © 2004,2007,2008,2009,2010 Red Hat, Inc. -Copyright © 1998-2004 David Turner and Werner Lemberg +Copyright © 2005,2006,2020,2021,2022,2023 Behdad Esfahbod +Copyright © 2004,2007,2008,2009,2010,2013,2021,2022,2023 Red Hat, Inc. +Copyright © 1998-2005 David Turner and Werner Lemberg +Copyright © 2016 Igalia S.L. +Copyright © 2022 Matthias Clasen +Copyright © 2018,2021 Khaled Hosny +Copyright © 2018,2019,2020 Adobe, Inc +Copyright © 2013-2015 Alexei Podtelezhnikov For full copyright notices consult the individual files in the package. diff --git a/libs/harfbuzz/Makefile.am b/libs/harfbuzz/Makefile.am deleted file mode 100644 index c14b4b7c2..000000000 --- a/libs/harfbuzz/Makefile.am +++ /dev/null @@ -1,82 +0,0 @@ -# Process this file with automake to produce Makefile.in - -NULL = - -ACLOCAL_AMFLAGS = -I m4 - -SUBDIRS = src util test perf docs - -EXTRA_DIST = \ - autogen.sh \ - harfbuzz.doap \ - README.md \ - README.python.md \ - BUILD.md \ - CONFIG.md \ - RELEASING.md \ - TESTING.md \ - CMakeLists.txt \ - replace-enum-strings.cmake \ - meson.build \ - meson_options.txt \ - subprojects/cairo.wrap \ - subprojects/freetype2.wrap \ - subprojects/glib.wrap \ - subprojects/google-benchmark.wrap \ - subprojects/ragel.wrap \ - subprojects/packagefiles/ragel/meson.build \ - mingw-configure.sh \ - $(NULL) - -MAINTAINERCLEANFILES = \ - $(GITIGNORE_MAINTAINERCLEANFILES_TOPLEVEL) \ - $(GITIGNORE_MAINTAINERCLEANFILES_M4_LIBTOOL) \ - $(GITIGNORE_MAINTAINERCLEANFILES_MAKEFILE_IN) \ - $(srcdir)/INSTALL \ - $(srcdir)/ChangeLog \ - $(srcdir)/gtk-doc.make \ - $(srcdir)/m4/gtk-doc.m4 \ - $(NULL) - - -# -# ChangeLog generation -# -CHANGELOG_RANGE = -ChangeLog: $(srcdir)/ChangeLog -$(srcdir)/ChangeLog: - $(AM_V_GEN) if test -d "$(top_srcdir)/.git"; then \ - (GIT_DIR=$(top_srcdir)/.git \ - $(GIT) log $(CHANGELOG_RANGE) --stat) > $@.tmp \ - && mv -f $@.tmp "$(srcdir)/ChangeLog" \ - || ($(RM) $@.tmp; \ - echo Failed to generate ChangeLog, your ChangeLog may be outdated >&2; \ - (test -f $@ || echo git-log is required to generate this file >> "$(srcdir)/$@")); \ - else \ - test -f $@ || \ - (echo A git checkout and git-log is required to generate ChangeLog >&2 && \ - echo A git checkout and git-log is required to generate this file >> "$(srcdir)/$@"); \ - fi -.PHONY: ChangeLog $(srcdir)/ChangeLog - - -# -# Release engineering -# - -DISTCHECK_CONFIGURE_FLAGS = \ - --enable-gtk-doc \ - --disable-doc-cross-references \ - --with-gobject \ - --enable-introspection \ - $(NULL) - -# TAR_OPTIONS is not set as env var for 'make dist'. How to fix that? -TAR_OPTIONS = --owner=0 --group=0 - -dist-hook: dist-clear-sticky-bits -# Clean up any sticky bits we may inherit from parent dir -dist-clear-sticky-bits: - chmod -R a-s $(distdir) - --include $(top_srcdir)/git.mk diff --git a/libs/harfbuzz/NEWS b/libs/harfbuzz/NEWS index 8d4389fc6..a2b6ebd23 100644 --- a/libs/harfbuzz/NEWS +++ b/libs/harfbuzz/NEWS @@ -1,3 +1,529 @@ +Overview of changes leading to 10.1.0 +Tuesday, November 5, 2024 +==================================== +- Fix the sign of fallback vertical glyph advance (used when font has no + vertical advance data). +- Increase maximum “CFF” operands limit 20 times to support more complex fonts. +- Add “--face-loader” option to command line utilities. +- Support “COLR” v0 table in hb_font_get_glyph_extents(). +- Add support for font functions that use Core Text APIs, similar to FreeType + font functions. This allows, for example, using drawing fonts that use the new + (and undocumented) “hvgl” table. +- Update IANA and OT language registries, as well ase USE data files. +- Fix build with ICU 76. +- Various compiler warnings and build fixes. +- Various subsetter fixes. + +- New API: ++hb_face_create_or_fail() ++hb_face_create_from_file_or_fail() ++hb_coretext_face_create_from_file_or_fail() ++hb_coretext_font_set_funcs() ++hb_ft_face_create_from_file_or_fail() + +Overview of changes leading to 10.0.1 +Tuesday, September 24, 2024 +==================================== +- Relax sanitization checks for “morx” subtables to fix broken AAT shaping of + macOS 15.0 version of GeezaPro. + + +Overview of changes leading to 10.0.0 +Monday, September 23, 2024 +==================================== +- Unicode 16.0.0 support. +- Various documentation fixes. +- Various build fixes. +- Add API to allow HarfBuzz client to set what glyph to use when a Unicode + Variation Selector is not supported by the font, which would allow the client + to customize what happens in this case, by using a different font for example. +- Add a callback to for “hb_face_t” for getting the list of table tags. This is + now used to make calling “hb_face_get_table_tags()” work on a faces created by + “hb_face_create_for_tables()” (e.g. faces returned by “hb_subset_or_fail()”). +- CGJ and Mongolian Variation Selectors are now ignored during glyph + positioning, previously they would block both glyph substitution and + positioning across them. +- Support cairo script as an output format for “hb-view” command line tool. +- Drop an optimization that would cause HarfBuzz not apply pair positioning + lookup subtables under certain circumstances, for compatibility with other + implementations that do apply these subtables. +- Subsetting will now fail if source font has no glyphs, so feeding the subsetter + invalid data will not silently return an empty face. +- If after partially instancing a font no variation data is left (the instance + is fully static), don’t consider this a failure. +- Workaround a Firefox bug in displaying SVGs generated be “hb-view” command + line tool under certain circumstances. +- Fix bug in macroman mapping for “cmap” table. +- Fix difference shaping output when HarfBuzz is built with with + “HB_NO_OT_RULESETS_FAST_PATH” enabled. +- Various subsetting and instancing fixes. +- Various fuzzing fixes. +- Add “with_libstdcxx” meson build option. + + +- New API: ++HB_SCRIPT_GARAY ++HB_SCRIPT_GURUNG_KHEMA ++HB_SCRIPT_KIRAT_RAI ++HB_SCRIPT_OL_ONAL ++HB_SCRIPT_SUNUWAR ++HB_SCRIPT_TODHRI ++HB_SCRIPT_TULU_TIGALARI ++hb_buffer_set_not_found_variation_selector_glyph() ++hb_buffer_get_not_found_variation_selector_glyph() ++hb_get_table_tags_func_t ++hb_face_set_get_table_tags_func() + + +Overview of changes leading to 9.0.0 +Thursday, Jun 27, 2024 +==================================== +- HarfBuzz now the supports the proposed new OpenType “VARC” table. This + replaces the previously supported “Variable Composites” experimental feature. + “VARC” support is still experimental and it is not enabled unless HarfBuzz is + built with experimental APIs enabled: + https://github.com/harfbuzz/boring-expansion-spec/blob/main/VARC.md +- Autotools build system have been dropped. Meson is the only supported build + system in HarfBuzz going forward. +- Speed up “AAT” shaping for short words by up to 4%. +- Ignore unknown “CFF” operators. +- “hb_subset_input_keep_everything()” now keeps also non-unicode “name” table + records. +- Update the IANA and OpenType language tag registries. +- Support composite glyphs with very large number of points in hb-draw API. +- Various build fixes. + + +Overview of changes leading to 8.5.0 +Monday, May 13, 2024 +==================================== +- API for partial instancing is now stable and have been promoted out of + experimental APIs. +- Support instancing “BASE” table. +- Speedup AAT shaping by 13–30%. +- Various build fixes. +- Various subsetter and instancer fixes. + +- New API: ++HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS ++hb_subset_input_get_axis_range() ++hb_subset_input_pin_axis_location() + +Overview of changes leading to 8.4.0 +Saturday, March 29, 2024 +==================================== +- Add /bigobj to MSVC compiler flags in meson build, to fix building hb-subset.cc +- Specify minimum versions of various dependencies in meson and autotools build. +- When subsetting, place variation store at the end of “GDEF” table to fix + shaping issues with some versions of Adobe InDesign. +- Various build fixes. + +- New API: ++hb_buffer_set_random_state() ++hb_buffer_get_random_state() + +Overview of changes leading to 8.3.1 +Saturday, March 16, 2024 +==================================== +- hb_blob_create_from_file_or_fail() on Windows will now try to interpret the + file name as UTF-8 first, and as system code page if it is not valid UTF-8. +- Fix hb_style_get_value() in fonts with “STAT” table. +- Properly handle negative offsets in CFF table. +- Update IANA Language Subtag Registry to 2024-03-07. +- Subsetter now supports subsetting “BASE” table. +- Subsetter will update “hhea” font metrics in sync with “OS/2” ones. +- “--variations” option of “hb-subset” now supports leaving out values that + should be unchanged, e.g. “wght=:500:” will change the default and keep max + and min unchanged. It also supports “*=drop” to to pin all axes to default + location. +- Fix hb_ot_math_get_glyph_kerning() to match updated “MATH” table spec. +- Support legacy MacRoman encoding in “cmap” table. +- Various build fixes. +- Various subsetting and instancing fixes. + +- New API: +hb_subset_input_pin_all_axes_to_default() + +Overview of changes leading to 8.3.0 +Saturday, November 11, 2023 +==================================== +- Improve memory barrier to fix potential segfaults. +- Various build fixes. +- Various subsetting and instancing fixes. +- Rename “hb-subset” option “--instance” to “--variations” to match the other + tools. Old option is kept as an alias. + +- New API: +HB_AAT_LAYOUT_FEATURE_TYPE_CURSIVE_CONNECTION + +- Deprecated API: +HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION + +Overview of changes leading to 8.2.2 +Wednesday, October 18, 2023 +“From the river to the sea, Palestine will be free” +==================================== +- Fix regression from 8.1.0 in shaping fonts with duplicate feature tags. +- Fix regression from 8.2.0 in parsing CSS-style feature strings. +- Variable fonts instanciation now handles more tables. +- Various CMake build improvements. +- various fixes to build without errors with gcc 4.9.2. + + +Overview of changes leading to 8.2.1 +Monday, September 18, 2023 +==================================== +- Unicode 15.1 support. + + +Overview of changes leading to 8.2.0 +Friday, September 8, 2023 +==================================== +- Various build and fuzzing fixes +- Improvements to COLRv1 painting. + +- New API: ++hb_paint_color_glyph_func_t ++hb_paint_funcs_set_color_glyph_func ++hb_paint_color_glyph + + +Overview of changes leading to 8.1.1 +Wednesday, August 2, 2023 +==================================== +- Fix shaping of contextual rules at the end of string, introduced in 8.1.0 +- Fix stack-overflow in repacker with malicious fonts. +- 30% speed up loading Noto Duployan font. + + +Overview of changes leading to 8.1.0 +Tuesday, August 1, 2023 +==================================== +- Fix long-standing build issue with the AIX compiler and older Apple clang. + +- Revert optimization that could cause timeout during subsetting with malicious fonts. + +- More optimization work: + - 45% speed up in shaping Noto Duployan font. + - 10% speed up in subsetting Noto Duployan font. + - Another 8% speed up in shaping Gulzar. + - 5% speed up in loading Roboto. + +- New API: ++hb_ot_layout_collect_features_map() + + +Overview of changes leading to 8.0.1 +Wednesday, July 12, 2023 +==================================== +- Build fix on 32-bit ARM. + +- More speed optimizations: + - 60% speed up in retain-gid (used for IFT) subsetting of SourceHanSans-VF. + - 16% speed up in retain-gid (used for IFT) subsetting of NotoSansCJKkr. + - 38% speed up in subsetting (beyond-64k) mega-merged Noto. + + +Overview of changes leading to 8.0.0 +Sunday, July 9, 2023 +==================================== +- New, experimental, WebAssembly (WASM) shaper, that provides greater + flexibility over OpenType/AAT/Graphite shaping, using WebAssembly embedded + inside the font file. Currently WASM shaper is disabled by default and needs + to be enabled at build time. For details, see: + + https://github.com/harfbuzz/harfbuzz/blob/main/docs/wasm-shaper.md + + For example fonts making use of the WASM shaper, see: + + https://github.com/harfbuzz/harfbuzz-wasm-examples + +- Improvements to Experimental features introduced in earlier releases: + - Support for subsetting beyond-64k and VarComposites fonts. + - Support for instancing variable fonts with cubic “glyf” table. + +- Many big speed optimizations: + - Up to 89% speedup loading variable fonts for shaping. + - Up to 88% speedup in small subsets of large (eg. CJK) fonts (both TTF and + OTF), essential for Incremental Font Transfer (IFT). + - Over 50% speedup in loading Roboto font for shaping. + - Up to 40% speed up in loading (sanitizing) complex fonts. + - 30% speed up in shaping Gulzar font. + - Over 25% speedup in glyph loading Roboto font. + - 10% speed up loading glyph shapes in VarComposite Hangul font. + - hb-hashmap optimizations & hashing improvements. + +- New macro HB_ALWAYS_INLINE. HarfBuzz now inlines functions more aggressively, + which results in some speedup at the expense of bigger code size. To disable + this feature define the macro to just inline. + +- New API: ++HB_CODEPOINT_INVALID ++hb_ot_layout_get_baseline2() ++hb_ot_layout_get_baseline_with_fallback2() ++hb_ot_layout_get_font_extents() ++hb_ot_layout_get_font_extents2() ++hb_subset_input_set_axis_range() + + +Overview of changes leading to 7.3.0 +Tuesday, May 9, 2023 +==================================== +- Speedup applying glyph variation in VarComposites fonts (over 40% speedup). + (Behdad Esfahbod) +- Speedup instancing some fonts (over 20% speedup in instancing RobotoFlex). + (Behdad Esfahbod) +- Speedup shaping some fonts (over 30% speedup in shaping Roboto). + (Behdad Esfahbod) +- Support subsetting VarComposites and beyond-64k fonts. (Behdad Esfahbod) +- New configuration macro HB_MINIMIZE_MEMORY_USAGE to favor optimizing memory + usage over speed. (Behdad Esfahbod) +- Supporting setting the mapping between old and new glyph indices during + subsetting. (Garret Rieger) +- Various fixes and improvements. + (Behdad Esfahbod, Denis Rochette, Garret Rieger, Han Seung Min, Qunxin Liu) + +- New API: ++hb_subset_input_old_to_new_glyph_mapping() + + +Overview of changes leading to 7.2.0 +Thursday, April 27, 2023 +==================================== +- Add Tifinagh to the list of scripts that can natively be either right-to-left + or left-to-right, to improve handling of its glyph positioning. + (Simon Cozens) +- Return also single substitution from hb_ot_layout_lookup_get_glyph_alternates() + (Behdad Esfahbod) +- Fix 4.2.0 regression in applying across syllables in syllabic scripts. + (Behdad Esfahbod) +- Add flag to avoid glyph substitution closure during subsetting, and the + corresponding “--no-layout-closure” option to “hb-subset” command line tool. + (Garret Rieger) +- Support instancing COLRv1 table. (Qunxin Liu) +- Don’t drop used user-defined name table entries during subsetting. + (Qunxin Liu) +- Optimize handling of “gvar” table. (Behdad Esfahbod) +- Various subsetter bug fixes and improvements. (Garret Rieger, Qunxin Liu) +- Various documentation improvements. (Behdad Esfahbod, Josef Friedrich) + +- New API: ++HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE ++HB_UNICODE_COMBINING_CLASS_CCC132 + +- Deprecated API: ++HB_UNICODE_COMBINING_CLASS_CCC133 + + +Overview of changes leading to 7.1.0 +Friday, March 3, 2023 +==================================== +- New experimental hb_shape_justify() API that uses font variations to expand + or shrink the text to a given advance. (Behdad Esfahbod) +- Various build and bug fixes. (Behdad Esfahbod, Garret Rieger, Qunxin Liu) + +- New API: ++hb_font_set_variation() + + +Overview of changes leading to 7.0.1 +Monday, February 20, 2023 +==================================== +- Various build and bug fixes. + + +Overview of changes leading to 7.0.0 +Saturday, February 11, 2023 +==================================== +- New hb-paint API that is designed mainly to paint “COLRv1” glyphs, but can be + also used as a unified API to paint any of the glyph representations + supported by HarfBuzz (B/W outlines, color layers, or color bitmaps). + (Behdad Esfahbod, Matthias Clasen) +- New hb-cairo API for integrating with cairo graphics library. This is provided + as a separate harfbuzz-cairo library. (Behdad Esfahbod, Matthias Clasen) +- Support for instancing “CFF2” table. (Behdad Esfahbod) +- Support font emboldening. (Behdad Esfahbod) +- Support feature ranges with AAT shaping. (Behdad Esfahbod) +- Experimental support to cubic curves in “glyf” table, see + https://github.com/harfbuzz/boring-expansion-spec/blob/main/glyf1-cubicOutlines.md + for spec. (Behdad Esfahbod) +- Various subsetter improvements. (Garret Rieger, Qunxin Liu, Behdad Esfahbod) +- Various documentation improvements. + (Behdad Esfahbod, Matthias Clasen, Khaled Hosny) +- Significantly reduced memory use during shaping. (Behdad Esfahbod) +- Greatly reduced memory use during subsetting “CFF” table. (Behdad Esfahbod) +- New command line utility, hb-info, for querying various font information. + (Behdad Esfahbod, Matthias Clasen) +- New hb-shape/hb-view options: --glyphs, --color-palette, --font-bold, + --font-grade, and --named-instance. (Behdad Esfahbod) +- Miscellaneous fixes and improvements. + (Amir Masoud Abdol, Andres Salomon, Behdad Esfahbod, Chun-wei Fan, + Garret Rieger, Jens Kutilek, Khaled Hosny, Konstantin Käfer, Matthias Clasen, + Nirbheek Chauhan, Pedro J. Estébanez, Qunxin Liu, Sergei Trofimovich) + +- New API: ++HB_FONT_NO_VAR_NAMED_INSTANCE ++HB_PAINT_IMAGE_FORMAT_BGRA ++HB_PAINT_IMAGE_FORMAT_PNG ++HB_PAINT_IMAGE_FORMAT_SVG ++hb_cairo_font_face_create_for_face ++hb_cairo_font_face_create_for_font ++hb_cairo_font_face_get_face ++hb_cairo_font_face_get_font ++hb_cairo_font_face_get_scale_factor ++hb_cairo_font_face_set_font_init_func ++hb_cairo_font_face_set_scale_factor ++hb_cairo_font_init_func_t ++hb_cairo_glyphs_from_buffer ++hb_cairo_scaled_font_get_font ++hb_color_line_get_color_stops ++hb_color_line_get_color_stops_func_t ++hb_color_line_get_extend ++hb_color_line_get_extend_func_t ++hb_color_line_t ++hb_color_stop_t ++hb_draw_funcs_get_empty ++hb_draw_funcs_get_user_data ++hb_draw_funcs_set_user_data ++hb_face_collect_nominal_glyph_mapping ++hb_font_draw_glyph ++hb_font_draw_glyph_func_t ++hb_font_funcs_set_draw_glyph_func ++hb_font_funcs_set_paint_glyph_func ++hb_font_get_synthetic_bold ++hb_font_get_var_named_instance ++hb_font_paint_glyph ++hb_font_paint_glyph_func_t ++hb_font_set_synthetic_bold ++hb_map_keys ++hb_map_next ++hb_map_update ++hb_map_values ++hb_ot_color_glyph_has_paint ++hb_ot_color_has_paint ++hb_ot_layout_script_select_language2 ++hb_ot_name_id_predefined_t ++hb_paint_color ++hb_paint_color_func_t ++hb_paint_composite_mode_t ++hb_paint_custom_palette_color ++hb_paint_custom_palette_color_func_t ++hb_paint_extend_t ++hb_paint_funcs_create ++hb_paint_funcs_destroy ++hb_paint_funcs_get_empty ++hb_paint_funcs_get_user_data ++hb_paint_funcs_is_immutable ++hb_paint_funcs_make_immutable ++hb_paint_funcs_reference ++hb_paint_funcs_set_color_func ++hb_paint_funcs_set_custom_palette_color_func ++hb_paint_funcs_set_image_func ++hb_paint_funcs_set_linear_gradient_func ++hb_paint_funcs_set_pop_clip_func ++hb_paint_funcs_set_pop_group_func ++hb_paint_funcs_set_pop_transform_func ++hb_paint_funcs_set_push_clip_glyph_func ++hb_paint_funcs_set_push_clip_rectangle_func ++hb_paint_funcs_set_push_group_func ++hb_paint_funcs_set_push_transform_func ++hb_paint_funcs_set_radial_gradient_func ++hb_paint_funcs_set_sweep_gradient_func ++hb_paint_funcs_set_user_data ++hb_paint_funcs_t ++hb_paint_image ++hb_paint_image_func_t ++hb_paint_linear_gradient ++hb_paint_linear_gradient_func_t ++hb_paint_pop_clip ++hb_paint_pop_clip_func_t ++hb_paint_pop_group ++hb_paint_pop_group_func_t ++hb_paint_pop_transform ++hb_paint_pop_transform_func_t ++hb_paint_push_clip_glyph ++hb_paint_push_clip_glyph_func_t ++hb_paint_push_clip_rectangle ++hb_paint_push_clip_rectangle_func_t ++hb_paint_push_group ++hb_paint_push_group_func_t ++hb_paint_push_transform ++hb_paint_push_transform_func_t ++hb_paint_radial_gradient ++hb_paint_radial_gradient_func_t ++hb_paint_sweep_gradient ++hb_paint_sweep_gradient_func_t ++hb_set_is_inverted ++hb_subset_input_keep_everything + +- Deprecated API: ++hb_font_funcs_set_glyph_shape_func ++hb_font_get_glyph_shape_func_t ++hb_font_get_glyph_shape + + +Overview of changes leading to 6.0.0 +Friday, December 16, 2022 +==================================== +- A new API have been added to pre-process the face and speed up future + subsetting operations on that face. Provides up to a 95% reduction in + subsetting times when the same face is subset more than once. + + For more details and benchmarks, see: + https://github.com/harfbuzz/harfbuzz/blob/main/docs/subset-preprocessing.md + + (Garret Rieger, Behdad Esfahbod) + +- Shaping have been speedup by skipping entire lookups when the buffer contents + don't intersect with the lookup. Shows up to a 10% speedup in shaping some + fonts. (Behdad Esfahbod) + +- A new experimental feature, “Variable Composites” (enabled by passing + -Dexperimental_api=true to meson), is also featured in this release. + This technology enables drastic compression of fonts in the Chinese, + Japanese, Korean, and other writing systems, by reusing the OpenType Font + Variations technology for encoding “smart components” into the font. + + The specification for these extensions to the font format can be found in: + https://github.com/harfbuzz/boring-expansion-spec/blob/glyf1/glyf1.md + + A test variable-font with ~7160 Hangul syllables derived from the + NotoSerifKR-VF font has been built, with existing OpenType technology, as + well as with the new Variable Composites (VarComposites) technology. The + VarComposites font is over 90% smaller than the OpenType version of the font! + Both fonts can be obtained from the “smarties” repository: + https://github.com/behdad/smarties/tree/3.0/fonts/hangul/serif + + When building HarfBuzz with experimental features enabled, you can test + the “smarties” font with a sample character like this: + + $ hb-view butchered-hangul-serif-smarties-variable.ttf -u AE01 --variations=wght=700 + + (Behdad Esfahbod) + +- The HarfBuzz subsetter can now drop axes by pinning them to specific values + (also referred to as instancing). There are a couple of restrictions + currently: + + - Only works with TrueType (“glyf”) based fonts. “CFF2” fonts are not yet + supported. + - Only supports the case where all axes in a font are pinned. + + (Garret Rieger, Qunxin Liu) + +- Miscellaneous fixes and improvements. + + (Behdad Esfahbod, Christoph Reiter, David Corbett, Eli Schwartz, Garret + Rieger, Joel Auterson, Jordan Petridis, Khaled Hosny, Lorenz Wildberg, + Marco Rebhan, Martin Storsjö, Matthias Clasen, Qunxin Liu, Satadru Pramanik) + + +- New API ++hb_subset_input_pin_axis_location() ++hb_subset_input_pin_axis_to_default() ++hb_subset_preprocess() + + Overview of changes leading to 5.3.1 Wednesday, October 19, 2022 ==================================== @@ -566,7 +1092,7 @@ Tuesday, March 16, 2021 Previously these were shaped using the generalized Arabic shaper. (David Corbett) - Fix regression in shaping of U+0B55 ORIYA SIGN OVERLINE. (David Corbett) - Update language tags. (David Corbett) -- Variations: reduce error: do not round each interpolated delta. (Just van Rossum) +- Variations: reduce error: do not round each interpolated delta. (Just van Rossum) - Documentation improvements. (Khaled Hosny, Nathan Willis) - Subsetter improvements: subsets most, if not all, lookup types now. (Garret Rieger, Qunxin Liu) - Fuzzer-found fixes and other improvements when memory failures happen. (Behdad) diff --git a/libs/harfbuzz/README b/libs/harfbuzz/README deleted file mode 100644 index 42061c01a..000000000 --- a/libs/harfbuzz/README +++ /dev/null @@ -1 +0,0 @@ -README.md \ No newline at end of file diff --git a/libs/harfbuzz/README.md b/libs/harfbuzz/README.md index 4202961e0..2cd8b4068 100644 --- a/libs/harfbuzz/README.md +++ b/libs/harfbuzz/README.md @@ -2,16 +2,21 @@ [![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) [![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://www.codacy.com/gh/harfbuzz/harfbuzz/dashboard?utm_source=github.com&utm_medium=referral&utm_content=harfbuzz/harfbuzz&utm_campaign=Badge_Grade) +[![Codacy Badge](https://app.codacy.com/project/badge/Grade/89c872f5ce1c42af802602bfcd15d90a)](https://app.codacy.com/gh/harfbuzz/harfbuzz/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) [![Codecov Code Coverage](https://codecov.io/gh/harfbuzz/harfbuzz/branch/main/graph/badge.svg)](https://codecov.io/gh/harfbuzz/harfbuzz) [![Packaging status](https://repology.org/badge/tiny-repos/harfbuzz.svg)](https://repology.org/project/harfbuzz/versions) +[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/harfbuzz/harfbuzz/badge)](https://securityscorecards.dev/viewer/?uri=github.com/harfbuzz/harfbuzz) + # HarfBuzz HarfBuzz is a text shaping engine. It primarily supports [OpenType][1], but also [Apple Advanced Typography][2]. HarfBuzz is used in Android, Chrome, -ChromeOS, Firefox, GNOME, GTK+, KDE, LibreOffice, OpenJDK, PlayStation, Qt, -XeTeX, and other places. +ChromeOS, Firefox, GNOME, GTK+, KDE, Qt, LibreOffice, OpenJDK, XeTeX, +PlayStation, Microsoft Edge, Adobe Photoshop, Illustrator, InDesign, +Godot Engine, Unreal Engine, and other places. + +[![xkcd-derived image](xkcd.png)](https://xkcd.com/2347/) For bug reports, mailing list, and other information please visit: @@ -26,8 +31,8 @@ For user manual as well as API documentation, check: https://harfbuzz.github.io ## Download For tarball releases of HarfBuzz, look [here][3]. At the same place you -will also find Win32/Win64 binary bundles that include libharfbuzz DLL, -hb-view.exe, hb-shape.exe, and all dependencies. +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]. @@ -47,8 +52,8 @@ For custom configurations, see [CONFIG.md](CONFIG.md). For testing and profiling, see [TESTING.md](TESTING.md). To get a better idea of where HarfBuzz stands in the text rendering stack you -may want to read [State of Text Rendering][6], though, that document is many -years old. Here are a few presentation slides about HarfBuzz at the +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: * November 2014, [Unicode, OpenType, and HarfBuzz: Closing the Circle][7], @@ -67,9 +72,9 @@ For a comparison of old vs new HarfBuzz memory consumption see [this][10]. ## Name -HarfBuzz (حرف‌باز) is my Persian translation of “[OpenType][1]”, -transliterated using the Latin script. It sports a second meaning, but that -ain’t translatable. +HarfBuzz (حرف‌باز) is the literal Persian translation of “[OpenType][1]”, +transliterated using the Latin script. It also means "talkative" or +"glib" (also a nod to the GNOME project where HarfBuzz originates from). > Background: Originally there was this font format called TrueType. People and > companies started calling their type engines all things ending in Type: @@ -92,7 +97,7 @@ ain’t translatable. [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/text/ +[6]: http://behdad.org/text2024 [7]: https://goo.gl/FSIQuC [8]: https://goo.gl/2wSRu [9]: http://behdad.org/download/Presentations/slippy/harfbuzz_slides.pdf diff --git a/libs/harfbuzz/README.mingw.md b/libs/harfbuzz/README.mingw.md deleted file mode 100644 index 60629f6fc..000000000 --- a/libs/harfbuzz/README.mingw.md +++ /dev/null @@ -1,58 +0,0 @@ -For the development of HarfBuzz, the Microsoft shaping technology, Uniscribe, -as a widely used and tested shaper is used as more-or-less OpenType reference -implementation and that specially is important where OpenType specification -is or wasn't that clear. For having access to Uniscribe on Linux/macOS these -steps are recommended: - -You want to follow the 32bit instructions. The 64bit equivalents are included -for reference. - -1. Install Wine. - - Fedora: `dnf install wine`. - -2. Install `mingw-w64` compiler. - - Fedora, 32bit: `dnf install mingw32-gcc-c++` - - Fedora, 64bit: `dnf install mingw64-gcc-c++` - - Debian: `apt install g++-mingw-w64` - - Mac: `brew install mingw-w64` - -3. If you have drank the `meson` koolaid, look at `.ci/build-win32.sh` to see how to - invoke `meson` now, or just run that script. Otherwise, here's how to use the - old trusty autotools instead: - - a) Install dependencies. - - Fedora, 32bit: `dnf install mingw32-glib2 mingw32-cairo mingw32-freetype` - - Fedora, 64bit: `dnf install mingw64-glib2 mingw64-cairo mingw64-freetype` - - b) Configure: - - `NOCONFIGURE=1 ./autogen.sh && mkdir winbuild && cd winbuild` - - 32bit: `../mingw-configure.sh i686` - - 64bit: `../mingw-configure.sh x86_64` - - c) Build as usual: - - make - - d) Configure your wine to find system mingw libraries. See: - https://fedoraproject.org/wiki/MinGW/Configure_wine - -Now you can use `hb-shape` by `(cd win32build/util && wine hb-shape.exe)` -but if you like to shape with the Microsoft Uniscribe: - -4. Bring a 32bit version of `usp10.dll` for yourself from `C:\Windows\SysWOW64\usp10.dll` of your - Windows installation (assuming you have a 64-bit installation, otherwise - `C:\Windows\System32\usp10.dll`) that it is not a DirectWrite proxy - ([for more info](https://en.wikipedia.org/wiki/Uniscribe)). - Rule of thumb, your `usp10.dll` should have a size more than 500kb, otherwise - it is designed to work with DirectWrite which Wine can't work with its original one. - You want a Uniscribe from Windows 7 or older. - - Put the DLL in the folder you are going to run the next command, - -5. `WINEDLLOVERRIDES="usp10=n" wine hb-shape.exe fontname.ttf -u 0061,0062,0063 --shaper=uniscribe` - -(`0061,0062,0063` means `abc`, use test/shaping/hb-unicode-decode to generate ones you need) - -When you have built that, you can test HarfBuzz's native shaper against Uniscribe -following these instructions: - - https://github.com/harfbuzz/harfbuzz/issues/3671 diff --git a/libs/harfbuzz/README.python.md b/libs/harfbuzz/README.python.md index 7496f045e..c945d08a8 100644 --- a/libs/harfbuzz/README.python.md +++ b/libs/harfbuzz/README.python.md @@ -9,9 +9,13 @@ sudo apt-get install libgirepository1.0-dev And then run `meson setup` and make sure that `Introspection` is reported enabled in output. +If you are building with Visual Studio, it is recommended that Visual Studio +2019 or later is used for this build, for the best build experience. + Compile and install. -Make sure you have the installation lib dir in `LD_LIBRARY_PATH`, as needed +Make sure you have the installation lib dir in `LD_LIBRARY_PATH` (or the +installation DLL dir in `PATH` for Windows systems), as needed for the linker to find the library. Then make sure you also have `GI_TYPELIB_PATH` pointing to the resulting diff --git a/libs/harfbuzz/RELEASING.md b/libs/harfbuzz/RELEASING.md index 8d5a4060b..e510022a2 100644 --- a/libs/harfbuzz/RELEASING.md +++ b/libs/harfbuzz/RELEASING.md @@ -17,15 +17,15 @@ - [ ] 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. +- [ ] 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. -- [ ] Bump version in line 3 of meson.build and configure.ac. +- [ ] Bump version in line 3 of meson.build. - [ ] 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, configure.ac, and src/hb-version.h, as well as any REPLACEME changes you made. +- [ ] 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" - [ ] Do a `meson dist -Cbuild` that runs the tests against the latest committed changes. diff --git a/libs/harfbuzz/SECURITY.md b/libs/harfbuzz/SECURITY.md new file mode 100644 index 000000000..69bb04456 --- /dev/null +++ b/libs/harfbuzz/SECURITY.md @@ -0,0 +1,20 @@ +# Security Policy + +If you have discovered a security vulnerability in this project, please report it +privately. **Do not disclose it as a public issue.** This gives me time to work with you +to fix the issue before public exposure, reducing the chance that the exploit will be +used before a patch is released. + +You may submit the report in the following ways: + +- send an email to behdad@behdad.org and harfbuzz-admin@googlegroups.com; and/or +- send me a [private vulnerability report](https://github.com/harfbuzz/harfbuzz/security/advisories/new) + +Please provide the following information in your report: + +- A description of the vulnerability and its impact +- How to reproduce the issue + +This project is mostly maintained by two developers, working on a reasonable effort +basis. As such, we ask that you give us 90 days to work on a fix before public +disclosure. diff --git a/libs/harfbuzz/autogen.sh b/libs/harfbuzz/autogen.sh deleted file mode 100644 index 085b4d863..000000000 --- a/libs/harfbuzz/autogen.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/sh -# Run this to generate all the initial makefiles, etc. - -test -n "$srcdir" || srcdir=`dirname "$0"` -test -n "$srcdir" || srcdir=. - -olddir=`pwd` -cd $srcdir - -#printf "checking for ragel... " -#which ragel || { -# echo "You need to install ragel... See http://www.complang.org/ragel/" -# exit 1 -#} - -printf "checking for pkg-config... " -which pkg-config || { - echo "*** No pkg-config found, please install it ***" - exit 1 -} - -printf "checking for libtoolize... " -which glibtoolize || which libtoolize || { - echo "*** No libtoolize (libtool) found, please install it ***" - exit 1 -} -printf "checking for gtkdocize... " -if which gtkdocize ; then - gtkdocize --copy || exit 1 -else - echo "*** No gtkdocize (gtk-doc) found, skipping documentation ***" - echo "EXTRA_DIST = " > gtk-doc.make -fi - -printf "checking for autoreconf... " -which autoreconf || { - echo "*** No autoreconf (autoconf) found, please install it ***" - exit 1 -} - -echo "running autoreconf --force --install --verbose" -autoreconf --force --install --verbose || exit $? - -cd $olddir -test -n "$NOCONFIGURE" || { - echo "running configure $@" - "$srcdir/configure" "$@" -} diff --git a/libs/harfbuzz/configure.ac b/libs/harfbuzz/configure.ac deleted file mode 100644 index f2480c349..000000000 --- a/libs/harfbuzz/configure.ac +++ /dev/null @@ -1,486 +0,0 @@ -AC_PREREQ([2.64]) -AC_INIT([HarfBuzz], - [5.3.1], - [https://github.com/harfbuzz/harfbuzz/issues/new], - [harfbuzz], - [http://harfbuzz.org/]) - -AC_CONFIG_MACRO_DIR([m4]) -AC_CONFIG_SRCDIR([src/harfbuzz.pc.in]) -AC_CONFIG_HEADERS([config.h]) - -AM_INIT_AUTOMAKE([1.13.0 gnits tar-ustar dist-xz no-dist-gzip -Wall no-define color-tests -Wno-portability]) -AM_SILENT_RULES([yes]) -AX_CODE_COVERAGE - -# Initialize libtool -m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) -LT_PREREQ([2.2]) -LT_INIT([disable-static]) - -# Check for programs -AC_PROG_CC -AC_PROG_CC_C99 -AM_PROG_CC_C_O -AC_PROG_CXX -AX_CXX_COMPILE_STDCXX(11) -AC_SYS_LARGEFILE -PKG_PROG_PKG_CONFIG([0.28]) -AM_MISSING_PROG([RAGEL], [ragel]) -AM_MISSING_PROG([GIT], [git]) - -# Version -m4_define(hb_version_triplet,m4_split(AC_PACKAGE_VERSION,[[.]])) -m4_define(hb_version_major,m4_argn(1,hb_version_triplet)) -m4_define(hb_version_minor,m4_argn(2,hb_version_triplet)) -m4_define(hb_version_micro,m4_argn(3,hb_version_triplet)) -HB_VERSION_MAJOR=hb_version_major -HB_VERSION_MINOR=hb_version_minor -HB_VERSION_MICRO=hb_version_micro -HB_VERSION=AC_PACKAGE_VERSION -AC_SUBST(HB_VERSION_MAJOR) -AC_SUBST(HB_VERSION_MINOR) -AC_SUBST(HB_VERSION_MICRO) -AC_SUBST(HB_VERSION) - -# Libtool version -m4_define([hb_version_int], - m4_eval(hb_version_major*10000 + hb_version_minor*100 + hb_version_micro)) -HB_LIBTOOL_VERSION_INFO=hb_version_int:0:hb_version_int -AC_SUBST(HB_LIBTOOL_VERSION_INFO) - -AC_ARG_WITH([libstdc++], - [AS_HELP_STRING([--with-libstdc++=@<:@yes/no@:>@], - [Allow linking with libstdc++ @<:@default=no@:>@])], - [with_libstdcxx=$withval], - [with_libstdcxx=no]) -AM_CONDITIONAL(WITH_LIBSTDCXX, [test "x$with_libstdcxx" = "xyes"]) - -# Documentation -have_gtk_doc=false -m4_ifdef([GTK_DOC_CHECK], [ -GTK_DOC_CHECK([1.15],[--flavour no-tmpl]) - if test "x$enable_gtk_doc" = xyes; then - have_gtk_doc=true - fi -], [ - AM_CONDITIONAL([ENABLE_GTK_DOC], false) -]) - -# Functions and headers -AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale uselocale) -AC_CHECK_HEADERS(unistd.h sys/mman.h stdbool.h xlocale.h) - -# Compiler flags -AC_CANONICAL_HOST -AC_CHECK_ALIGNOF([struct{char;}]) -if test "x$GCC" = "xyes"; then - - # Make symbols link locally - AX_CHECK_LINK_FLAG([[-Bsymbolic-functions]], [LDFLAGS="$LDFLAGS -Bsymbolic-functions"]) - - # Make it possible to not link to libstdc++ - # No threadsafe statics in C++ as we do it ourselves. - # We don't use these features, so it's safe to disable them - # even in the cases where we DO link to libstdc++. - # Put -fno-rtti before $CXXFLAGS such that users can re-enable it - # by overriding CXXFLAGS. - CXXFLAGS="-fno-rtti $CXXFLAGS -fno-exceptions -fno-threadsafe-statics" - - case "$host" in - *-*-mingw*) - ;; - *) - # Hide inline methods - CXXFLAGS="$CXXFLAGS -fvisibility-inlines-hidden" - ;; - esac - - case "$host" in - arm-*-*) - if test "x$ac_cv_alignof_struct_char__" != x1; then - # Request byte alignment - CXXFLAGS="$CXXFLAGS -mstructure-size-boundary=8" - fi - ;; - esac -fi - -AM_CONDITIONAL(HAVE_GCC, test "x$GCC" = "xyes") - -hb_os_win32=no -AC_MSG_CHECKING([for native Win32]) -case "$host" in - *-*-mingw*) - hb_os_win32=yes - ;; -esac -AC_MSG_RESULT([$hb_os_win32]) -AM_CONDITIONAL(OS_WIN32, test "$hb_os_win32" = "yes") - -have_pthread=false -AX_PTHREAD([have_pthread=true]) -if $have_pthread; then - AC_DEFINE(HAVE_PTHREAD, 1, [Have POSIX threads]) -fi -AM_CONDITIONAL(HAVE_PTHREAD, $have_pthread) - -dnl ========================================================================== - -AC_ARG_WITH(glib, - [AS_HELP_STRING([--with-glib=@<:@yes/no/auto@:>@], - [Use glib @<:@default=auto@:>@])],, - [with_glib=auto]) -have_glib=false -GLIB_DEPS="glib-2.0 >= 2.19.1" -AC_SUBST(GLIB_DEPS) -if test "x$with_glib" = "xyes" -o "x$with_glib" = "xauto"; then - PKG_CHECK_MODULES(GLIB, $GLIB_DEPS, have_glib=true, :) -fi -if test "x$with_glib" = "xyes" -a "x$have_glib" != "xtrue"; then - AC_MSG_ERROR([glib support requested but glib-2.0 not found]) -fi -if $have_glib; then - AC_DEFINE(HAVE_GLIB, 1, [Have glib2 library]) -fi -AM_CONDITIONAL(HAVE_GLIB, $have_glib) - -dnl =========================================================================== - -AC_ARG_WITH(gobject, - [AS_HELP_STRING([--with-gobject=@<:@yes/no/auto@:>@], - [Use gobject @<:@default=no@:>@])],, - [with_gobject=no]) -have_gobject=false -if test "x$with_gobject" = "xyes" -o "x$with_gobject" = "xauto"; then - PKG_CHECK_MODULES(GOBJECT, gobject-2.0 glib-2.0, have_gobject=true, :) -fi -if test "x$with_gobject" = "xyes" -a "x$have_gobject" != "xtrue"; then - AC_MSG_ERROR([gobject support requested but gobject-2.0 / glib-2.0 not found]) -fi -if $have_gobject; then - AC_DEFINE(HAVE_GOBJECT, 1, [Have gobject2 library]) - GLIB_MKENUMS=`$PKG_CONFIG --variable=glib_mkenums glib-2.0` - AC_SUBST(GLIB_MKENUMS) -fi -AM_CONDITIONAL(HAVE_GOBJECT, $have_gobject) -AC_SUBST(have_gobject) - -dnl =========================================================================== - - -dnl =========================================================================== -# Gobject-Introspection -have_introspection=false -m4_ifdef([GOBJECT_INTROSPECTION_CHECK], [ - if $have_gobject; then - GOBJECT_INTROSPECTION_CHECK([1.34.0]) - if test "x$found_introspection" = xyes; then - have_introspection=true - fi - else - AM_CONDITIONAL([HAVE_INTROSPECTION], false) - fi -], [ - AM_CONDITIONAL([HAVE_INTROSPECTION], false) -]) - -dnl ========================================================================== - -AC_ARG_WITH(cairo, - [AS_HELP_STRING([--with-cairo=@<:@yes/no/auto@:>@], - [Use cairo @<:@default=auto@:>@])],, - [with_cairo=auto]) -have_cairo=false -if test "x$with_cairo" = "xyes" -o "x$with_cairo" = "xauto"; then - PKG_CHECK_MODULES(CAIRO, cairo >= 1.8.0, have_cairo=true, :) - save_libs=$LIBS - LIBS="$LIBS $CAIRO_LIBS" - AC_CHECK_FUNCS(cairo_user_font_face_set_render_color_glyph_func) - LIBS=$save_libs -fi -if test "x$with_cairo" = "xyes" -a "x$have_cairo" != "xtrue"; then - AC_MSG_ERROR([cairo support requested but not found]) -fi -if $have_cairo; then - AC_DEFINE(HAVE_CAIRO, 1, [Have cairo graphics library]) -fi -AM_CONDITIONAL(HAVE_CAIRO, $have_cairo) - -have_cairo_ft=false -if $have_cairo; then - PKG_CHECK_MODULES(CAIRO_FT, cairo-ft, have_cairo_ft=true, :) -fi -if $have_cairo_ft; then - AC_DEFINE(HAVE_CAIRO_FT, 1, [Have cairo-ft support in cairo graphics library]) -fi -AM_CONDITIONAL(HAVE_CAIRO_FT, $have_cairo_ft) - -dnl ========================================================================== - -AC_ARG_WITH(chafa, - [AS_HELP_STRING([--with-chafa=@<:@yes/no/auto@:>@], - [Use chafa @<:@default=auto@:>@])],, - [with_chafa=auto]) -have_chafa=false -if test "x$with_chafa" = "xyes" -o "x$with_chafa" = "xauto"; then - PKG_CHECK_MODULES(CHAFA, chafa >= 1.6.0, have_chafa=true, :) -fi -if test "x$with_chafa" = "xyes" -a "x$have_chafa" != "xtrue"; then - AC_MSG_ERROR([chafa support requested but not found]) -fi -if $have_chafa; then - AC_DEFINE(HAVE_CHAFA, 1, [Have chafa terminal graphics library]) -fi -AM_CONDITIONAL(HAVE_CHAFA, $have_chafa) - -dnl ========================================================================== - -AC_ARG_WITH(icu, - [AS_HELP_STRING([--with-icu=@<:@yes/no/builtin/auto@:>@], - [Use ICU @<:@default=auto@:>@])],, - [with_icu=auto]) -have_icu=false -if test "x$with_icu" = "xyes" -o "x$with_icu" = "xbuiltin" -o "x$with_icu" = "xauto"; then - PKG_CHECK_MODULES(ICU, icu-uc, have_icu=true, :) -fi -if test \( "x$with_icu" = "xyes" -o "x$with_icu" = "xbuiltin" \) -a "x$have_icu" != "xtrue"; then - AC_MSG_ERROR([icu support requested but icu-uc not found]) -fi - -if $have_icu; then - CXXFLAGS="$CXXFLAGS `$PKG_CONFIG --variable=CXXFLAGS icu-uc`" - AC_DEFINE(HAVE_ICU, 1, [Have ICU library]) - if test "x$with_icu" = "xbuiltin"; then - AC_DEFINE(HAVE_ICU_BUILTIN, 1, [Use hb-icu Unicode callbacks]) - fi -fi -AM_CONDITIONAL(HAVE_ICU, $have_icu) -AM_CONDITIONAL(HAVE_ICU_BUILTIN, $have_icu && test "x$with_icu" = "xbuiltin") - -dnl =========================================================================== - -AC_ARG_WITH(graphite2, - [AS_HELP_STRING([--with-graphite2=@<:@yes/no/auto@:>@], - [Use the graphite2 library @<:@default=no@:>@])],, - [with_graphite2=no]) -have_graphite2=false -GRAPHITE2_DEPS="graphite2 >= 1.2.0" -AC_SUBST(GRAPHITE2_DEPS) -if test "x$with_graphite2" = "xyes" -o "x$with_graphite2" = "xauto"; then - PKG_CHECK_MODULES(GRAPHITE2, $GRAPHITE2_DEPS, have_graphite2=true, :) - if test "x$have_graphite2" != "xtrue"; then - # If pkg-config is not available, graphite2 can still be there - ac_save_CFLAGS="$CFLAGS" - ac_save_CPPFLAGS="$CPPFLAGS" - CFLAGS="$CFLAGS $GRAPHITE2_CFLAGS" - CPPFLAGS="$CPPFLAGS $GRAPHITE2_CFLAGS" - AC_CHECK_HEADER(graphite2/Segment.h, have_graphite2=true, :) - CPPFLAGS="$ac_save_CPPFLAGS" - CFLAGS="$ac_save_CFLAGS" - fi -fi -if test "x$with_graphite2" = "xyes" -a "x$have_graphite2" != "xtrue"; then - AC_MSG_ERROR([graphite2 support requested but libgraphite2 not found]) -fi -if $have_graphite2; then - AC_DEFINE(HAVE_GRAPHITE2, 1, [Have Graphite2 library]) -fi -AM_CONDITIONAL(HAVE_GRAPHITE2, $have_graphite2) - -dnl ========================================================================== - -AC_ARG_WITH(freetype, - [AS_HELP_STRING([--with-freetype=@<:@yes/no/auto@:>@], - [Use the FreeType library @<:@default=auto@:>@])],, - [with_freetype=auto]) -have_freetype=false -FREETYPE_DEPS="freetype2 >= 12.0.6" -AC_SUBST(FREETYPE_DEPS) -if test "x$with_freetype" = "xyes" -o "x$with_freetype" = "xauto"; then - # See freetype/docs/VERSION.DLL; 12.0.6 means freetype-2.4.2 - PKG_CHECK_MODULES(FREETYPE, $FREETYPE_DEPS, have_freetype=true, :) -fi -if test "x$with_freetype" = "xyes" -a "x$have_freetype" != "xtrue"; then - AC_MSG_ERROR([FreeType support requested but libfreetype2 not found]) -fi -if $have_freetype; then - AC_DEFINE(HAVE_FREETYPE, 1, [Have FreeType 2 library]) - save_libs=$LIBS - LIBS="$LIBS $FREETYPE_LIBS" - AC_CHECK_FUNCS(FT_Get_Var_Blend_Coordinates FT_Set_Var_Blend_Coordinates FT_Done_MM_Var FT_Get_Transform) - LIBS=$save_libs -fi -AM_CONDITIONAL(HAVE_FREETYPE, $have_freetype) - -dnl =========================================================================== - -AC_ARG_WITH(uniscribe, - [AS_HELP_STRING([--with-uniscribe=@<:@yes/no/auto@:>@], - [Use the Uniscribe library @<:@default=no@:>@])],, - [with_uniscribe=no]) -have_uniscribe=false -if test "x$with_uniscribe" = "xyes" -o "x$with_uniscribe" = "xauto"; then - AC_CHECK_HEADERS(usp10.h windows.h, have_uniscribe=true) -fi -if test "x$with_uniscribe" = "xyes" -a "x$have_uniscribe" != "xtrue"; then - AC_MSG_ERROR([uniscribe support requested but not found]) -fi -if $have_uniscribe; then - UNISCRIBE_CFLAGS= - UNISCRIBE_LIBS="-lusp10 -lgdi32 -lrpcrt4" - AC_SUBST(UNISCRIBE_CFLAGS) - AC_SUBST(UNISCRIBE_LIBS) - AC_DEFINE(HAVE_UNISCRIBE, 1, [Have Uniscribe library]) -fi -AM_CONDITIONAL(HAVE_UNISCRIBE, $have_uniscribe) - -dnl =========================================================================== - -AC_ARG_WITH(gdi, - [AS_HELP_STRING([--with-gdi=@<:@yes/no/auto@:>@], - [Provide GDI integration helpers @<:@default=no@:>@])],, - [with_gdi=no]) -have_gdi=false -if test "x$with_gdi" = "xyes" -o "x$with_gdi" = "xauto"; then - AC_CHECK_HEADERS(windows.h, have_gdi=true) -fi -if test "x$with_gdi" = "xyes" -a "x$have_gdi" != "xtrue"; then - AC_MSG_ERROR([gdi support requested but not found]) -fi -if $have_gdi; then - GDI_CFLAGS= - GDI_LIBS="-lgdi32" - AC_SUBST(GDI_CFLAGS) - AC_SUBST(GDI_LIBS) - AC_DEFINE(HAVE_GDI, 1, [Have GDI library]) -fi -AM_CONDITIONAL(HAVE_GDI, $have_gdi) - -dnl =========================================================================== - -AC_ARG_WITH(directwrite, - [AS_HELP_STRING([--with-directwrite=@<:@yes/no/auto@:>@], - [Use the DirectWrite library (experimental) @<:@default=no@:>@])],, - [with_directwrite=no]) -have_directwrite=false -AC_LANG_PUSH([C++]) -if test "x$with_directwrite" = "xyes" -o "x$with_directwrite" = "xauto"; then - AC_CHECK_HEADERS(dwrite_1.h, have_directwrite=true) -fi -AC_LANG_POP([C++]) -if test "x$with_directwrite" = "xyes" -a "x$have_directwrite" != "xtrue"; then - AC_MSG_ERROR([directwrite support requested but not found]) -fi -if $have_directwrite; then - AC_DEFINE(HAVE_DIRECTWRITE, 1, [Have DirectWrite library]) -fi -AM_CONDITIONAL(HAVE_DIRECTWRITE, $have_directwrite) - -dnl =========================================================================== - -AC_ARG_WITH(coretext, - [AS_HELP_STRING([--with-coretext=@<:@yes/no/auto@:>@], - [Use CoreText @<:@default=no@:>@])],, - [with_coretext=no]) -have_coretext=false -if test "x$with_coretext" = "xyes" -o "x$with_coretext" = "xauto"; then - AC_CHECK_TYPE(CTFontRef, have_coretext=true,, [#include ]) - - if $have_coretext; then - CORETEXT_CFLAGS= - CORETEXT_LIBS="-framework ApplicationServices" - AC_SUBST(CORETEXT_CFLAGS) - AC_SUBST(CORETEXT_LIBS) - else - # On iOS CoreText and CoreGraphics are stand-alone frameworks - if test "x$have_coretext" != "xtrue"; then - # Check for a different symbol to avoid getting cached result. - AC_CHECK_TYPE(CTRunRef, have_coretext=true,, [#include ]) - fi - - if $have_coretext; then - CORETEXT_CFLAGS= - CORETEXT_LIBS="-framework CoreText -framework CoreGraphics -framework CoreFoundation" - AC_SUBST(CORETEXT_CFLAGS) - AC_SUBST(CORETEXT_LIBS) - fi - fi -fi -if test "x$with_coretext" = "xyes" -a "x$have_coretext" != "xtrue"; then - AC_MSG_ERROR([CoreText support requested but libcoretext not found]) -fi -if $have_coretext; then - AC_DEFINE(HAVE_CORETEXT, 1, [Have Core Text backend]) -fi -AM_CONDITIONAL(HAVE_CORETEXT, $have_coretext) - -dnl =========================================================================== - -AC_CONFIG_FILES([ -Makefile -src/Makefile -src/harfbuzz-config.cmake -util/Makefile -test/Makefile -test/api/Makefile -test/fuzzing/Makefile -test/shape/Makefile -test/shape/data/Makefile -test/shape/data/aots/Makefile -test/shape/data/in-house/Makefile -test/shape/data/text-rendering-tests/Makefile -test/subset/Makefile -test/subset/data/Makefile -test/subset/data/repack_tests/Makefile -test/threads/Makefile -perf/Makefile -docs/Makefile -docs/version.xml -]) - -AC_OUTPUT - -echo -echo "C++ compiler version:" -$CXX --version -echo - -AC_MSG_NOTICE([ - -Autotools is no longer our supported build system for building the library -for *nix distributions, please migrate to meson. - -]) - - -AC_MSG_NOTICE([ - -Build configuration: - -Unicode callbacks (you want at least one): - Builtin true - Glib: ${have_glib} - ICU: ${have_icu} - -Font callbacks (the more the merrier): - FreeType: ${have_freetype} - -Tools used for command-line utilities: - Cairo: ${have_cairo} - Chafa: ${have_chafa} - -Additional shapers: - Graphite2: ${have_graphite2} - -Platform shapers (not normally needed): - CoreText: ${have_coretext} - DirectWrite: ${have_directwrite} - GDI: ${have_gdi} - Uniscribe: ${have_uniscribe} - -Other features: - Documentation: ${enable_gtk_doc} - GObject bindings: ${have_gobject} - Introspection: ${have_introspection} -]) diff --git a/libs/harfbuzz/docs/Makefile.am b/libs/harfbuzz/docs/Makefile.am deleted file mode 100644 index 36da8ae37..000000000 --- a/libs/harfbuzz/docs/Makefile.am +++ /dev/null @@ -1,123 +0,0 @@ -# Process this file with automake to produce Makefile.in - -# We require automake 1.6 at least. -AUTOMAKE_OPTIONS = 1.6 - -# This is a blank Makefile.am for using gtk-doc. -# Copy this to your project's API docs directory and modify the variables to -# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples -# of using the various options. - -# The name of the module, e.g. 'glib'. -DOC_MODULE=harfbuzz - -# Uncomment for versioned docs and specify the version of the module, e.g. '2'. -#DOC_MODULE_VERSION=$(HB_VERSION_MAJOR) - -# The top-level SGML file. You can change this if you want to. -DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml - -# Directories containing the source code. -# gtk-doc will search all .c and .h files beneath these paths -# for inline comments documenting functions and macros. -# e.g. DOC_SOURCE_DIR=$(top_srcdir)/gtk $(top_srcdir)/gdk -DOC_SOURCE_DIR=$(top_srcdir)/src $(top_builddir)/src - -# Extra options to pass to gtkdoc-scangobj. Not normally needed. -SCANGOBJ_OPTIONS= - -# Extra options to supply to gtkdoc-scan. -# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED" -SCAN_OPTIONS=--rebuild-types --deprecated-guards="HB_DISABLE_DEPRECATED" \ - --ignore-decorators='HB_EXTERN|HB_DEPRECATED' - -# Header files or dirs to ignore when scanning. Use base file/dir names -# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code -IGNORE_HFILES=`cd $(top_srcdir)/src; find . -path './*/*.h' | sed 's@^.*/@@'` -IGNORE_HFILES+=hb-gobject.h hb-gobject-enums.h hb-gobject-structs.h - -# Extra options to supply to gtkdoc-mkdb. -# e.g. MKDB_OPTIONS=--xml-mode --output-format=xml -MKDB_OPTIONS=--source-suffixes=h,cc --xml-mode --output-format=xml --ignore-files="$(IGNORE_HFILES)" - -# Extra options to supply to gtkdoc-mktmpl -# e.g. MKTMPL_OPTIONS=--only-section-tmpl -MKTMPL_OPTIONS= - -# Extra options to supply to gtkdoc-mkhtml -MKHTML_OPTIONS= - -# Extra options to supply to gtkdoc-fixref. Not normally needed. -# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html -FIXXREF_OPTIONS= - -# Used for dependencies. The docs will be rebuilt if any of these change. -# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h -# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c -HFILE_GLOB=$(top_srcdir)/src/hb.h $(top_srcdir)/src/hb-*.h -CFILE_GLOB=$(top_srcdir)/src/hb-*.cc - -# Extra header to include when scanning, which are not under DOC_SOURCE_DIR -# e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h - -# Images to copy into HTML directory. -# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png -HTML_IMAGES= \ - HarfBuzz.png \ - HarfBuzz.svg - -# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). -# e.g. content_files=running.sgml building.sgml changes-2.0.sgml -content_files= \ - usermanual-what-is-harfbuzz.xml \ - usermanual-install-harfbuzz.xml \ - usermanual-getting-started.xml \ - usermanual-glyph-information.xml \ - usermanual-shaping-concepts.xml \ - usermanual-object-model.xml \ - usermanual-buffers-language-script-and-direction.xml \ - usermanual-fonts-and-faces.xml \ - usermanual-opentype-features.xml \ - usermanual-clusters.xml \ - usermanual-utilities.xml \ - usermanual-integration.xml \ - version.xml - -# SGML files where gtk-doc abbreviations (#GtkWidget) are expanded -# These files must be listed here *and* in content_files -# e.g. expand_content_files=running.sgml -expand_content_files= - -# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library. -# Only needed if you are using gtkdoc-scangobj to dynamically query widget -# signals and properties. -# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS) -# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib) -GTKDOC_CFLAGS= -GTKDOC_LIBS=$(top_builddir)/src/libharfbuzz.la -if HAVE_GOBJECT -GTKDOC_LIBS+=$(top_builddir)/src/libharfbuzz-gobject.la -endif - -# This includes the standard gtk-doc make rules, copied by gtkdocize. -include $(top_srcdir)/gtk-doc.make - -# Other files to distribute -# e.g. EXTRA_DIST += version.xml.in -EXTRA_DIST += version.xml.in meson.build - -# Files not to distribute -# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types -# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt -#DISTCLEANFILES += - -# Comment this out if you don't want 'make check' to test you doc status -# and run some sanity checks -if ENABLE_GTK_DOC -TESTS_ENVIRONMENT = cd $(srcdir) && \ - DOC_MODULE=$(DOC_MODULE) DOC_MAIN_SGML_FILE=$(DOC_MAIN_SGML_FILE) \ - SRCDIR=$(abs_srcdir) BUILDDIR=$(abs_builddir) -#TESTS = $(GTKDOC_CHECK) -endif - --include $(top_srcdir)/git.mk diff --git a/libs/harfbuzz/docs/harfbuzz-docs.xml b/libs/harfbuzz/docs/harfbuzz-docs.xml index 652a5e470..164b89299 100644 --- a/libs/harfbuzz/docs/harfbuzz-docs.xml +++ b/libs/harfbuzz/docs/harfbuzz-docs.xml @@ -56,7 +56,9 @@ + + @@ -96,6 +98,7 @@ + @@ -115,76 +118,88 @@ API Index - Index of deprecated API - - Index of new symbols in 5.3.0 - Index of new symbols in 5.0.0 - Index of new symbols in 4.4.0 - Index of new symbols in 4.3.0 - Index of new symbols in 4.2.0 - Index of new symbols in 4.1.0 - Index of new symbols in 4.0.0 - Index of new symbols in 3.4.0 - Index of new symbols in 3.3.0 - Index of new symbols in 3.1.0 - Index of new symbols in 3.0.0 - Index of new symbols in 2.9.1 - Index of new symbols in 2.9.0 - Index of new symbols in 2.8.2 - Index of new symbols in 2.7.3 - Index of new symbols in 2.6.8 - Index of new symbols in 2.6.5 - Index of new symbols in 2.6.3 - Index of new symbols in 2.6.0 - Index of new symbols in 2.5.0 - Index of new symbols in 2.4.0 - Index of new symbols in 2.3.0 - Index of new symbols in 2.2.0 - Index of new symbols in 2.1.0 - Index of new symbols in 2.0.0 - Index of new symbols in 1.9.0 - Index of new symbols in 1.8.6 - Index of new symbols in 1.8.5 - Index of new symbols in 1.8.1 - Index of new symbols in 1.8.0 - Index of new symbols in 1.7.7 - Index of new symbols in 1.7.2 - Index of new symbols in 1.6.0 - Index of new symbols in 1.5.0 - Index of new symbols in 1.4.3 - Index of new symbols in 1.4.2 - Index of new symbols in 1.4.0 - Index of new symbols in 1.3.3 - Index of new symbols in 1.2.3 - Index of new symbols in 1.1.3 - Index of new symbols in 1.1.2 - Index of new symbols in 1.0.5 - Index of new symbols in 0.9.42 - Index of new symbols in 0.9.41 - Index of new symbols in 0.9.39 - Index of new symbols in 0.9.38 - Index of new symbols in 0.9.33 - Index of new symbols in 0.9.31 - Index of new symbols in 0.9.30 - Index of new symbols in 0.9.28 - Index of new symbols in 0.9.26 - Index of new symbols in 0.9.22 - Index of new symbols in 0.9.21 - Index of new symbols in 0.9.20 - Index of new symbols in 0.9.11 - Index of new symbols in 0.9.10 - Index of new symbols in 0.9.8 - Index of new symbols in 0.9.7 - Index of new symbols in 0.9.5 - Index of new symbols in 0.9.2 - Index of new symbols in 0.6.0 + Index of deprecated API + + Index of new symbols in 10.1.0 + Index of new symbols in 10.0.0 + Index of new symbols in 8.5.0 + Index of new symbols in 8.4.0 + Index of new symbols in 8.3.1 + Index of new symbols in 8.2.0 + Index of new symbols in 8.1.0 + Index of new symbols in 8.0.0 + Index of new symbols in 7.3.0 + Index of new symbols in 7.1.0 + Index of new symbols in 7.0.0 + Index of new symbols in 6.0.0 + Index of new symbols in 5.3.0 + Index of new symbols in 5.0.0 + Index of new symbols in 4.4.0 + Index of new symbols in 4.3.0 + Index of new symbols in 4.2.0 + Index of new symbols in 4.1.0 + Index of new symbols in 4.0.0 + Index of new symbols in 3.4.0 + Index of new symbols in 3.3.0 + Index of new symbols in 3.1.0 + Index of new symbols in 3.0.0 + Index of new symbols in 2.9.1 + Index of new symbols in 2.9.0 + Index of new symbols in 2.8.2 + Index of new symbols in 2.7.3 + Index of new symbols in 2.6.8 + Index of new symbols in 2.6.5 + Index of new symbols in 2.6.3 + Index of new symbols in 2.6.0 + Index of new symbols in 2.5.0 + Index of new symbols in 2.4.0 + Index of new symbols in 2.3.0 + Index of new symbols in 2.2.0 + Index of new symbols in 2.1.0 + Index of new symbols in 2.0.0 + Index of new symbols in 1.9.0 + Index of new symbols in 1.8.6 + Index of new symbols in 1.8.5 + Index of new symbols in 1.8.1 + Index of new symbols in 1.8.0 + Index of new symbols in 1.7.7 + Index of new symbols in 1.7.2 + Index of new symbols in 1.6.0 + Index of new symbols in 1.5.0 + Index of new symbols in 1.4.3 + Index of new symbols in 1.4.2 + Index of new symbols in 1.4.0 + Index of new symbols in 1.3.3 + Index of new symbols in 1.2.3 + Index of new symbols in 1.1.3 + Index of new symbols in 1.1.2 + Index of new symbols in 1.0.5 + Index of new symbols in 0.9.42 + Index of new symbols in 0.9.41 + Index of new symbols in 0.9.39 + Index of new symbols in 0.9.38 + Index of new symbols in 0.9.33 + Index of new symbols in 0.9.31 + Index of new symbols in 0.9.30 + Index of new symbols in 0.9.28 + Index of new symbols in 0.9.26 + Index of new symbols in 0.9.22 + Index of new symbols in 0.9.21 + Index of new symbols in 0.9.20 + Index of new symbols in 0.9.11 + Index of new symbols in 0.9.10 + Index of new symbols in 0.9.8 + Index of new symbols in 0.9.7 + Index of new symbols in 0.9.5 + Index of new symbols in 0.9.2 + Index of new symbols in 0.6.0 - The current HarfBuzz codebase is versioned 2.x.x and is stable + The current HarfBuzz codebase is stable and under active maintenance. This is what is used in latest versions of Firefox, GNOME, ChromeOS, Chrome, LibreOffice, XeTeX, Android, and KDE, among other places. diff --git a/libs/harfbuzz/docs/harfbuzz-sections.txt b/libs/harfbuzz/docs/harfbuzz-sections.txt index 3a7aa358c..4a5c06cd6 100644 --- a/libs/harfbuzz/docs/harfbuzz-sections.txt +++ b/libs/harfbuzz/docs/harfbuzz-sections.txt @@ -1,9 +1,3 @@ - -HB_H_IN -HB_OT_H_IN -HB_AAT_H_IN - -
hb-aat-layout HB_AAT_LAYOUT_NO_SELECTOR_INDEX @@ -26,33 +20,33 @@ hb_blob_create_from_file hb_blob_create_from_file_or_fail hb_blob_create_sub_blob hb_blob_copy_writable_or_fail +hb_blob_get_empty +hb_blob_reference hb_blob_destroy +hb_blob_set_user_data +hb_blob_get_user_data +hb_blob_make_immutable +hb_blob_is_immutable hb_blob_get_data hb_blob_get_data_writable -hb_blob_get_empty hb_blob_get_length -hb_blob_get_user_data -hb_blob_is_immutable -hb_blob_make_immutable -hb_blob_reference -hb_blob_set_user_data hb_blob_t hb_memory_mode_t
hb-buffer -HB_SEGMENT_PROPERTIES_DEFAULT -HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT hb_buffer_create +hb_buffer_allocation_successful hb_buffer_create_similar -hb_buffer_reference hb_buffer_get_empty +hb_buffer_reference hb_buffer_destroy +hb_buffer_set_user_data +hb_buffer_get_user_data hb_buffer_reset hb_buffer_clear_contents hb_buffer_pre_allocate -hb_buffer_allocation_successful hb_buffer_add hb_buffer_add_codepoints hb_buffer_add_utf32 @@ -79,17 +73,20 @@ hb_buffer_get_segment_properties hb_buffer_guess_segment_properties hb_buffer_set_unicode_funcs hb_buffer_get_unicode_funcs -hb_buffer_set_user_data -hb_buffer_get_user_data hb_buffer_get_glyph_infos +hb_glyph_info_get_glyph_flags hb_buffer_get_glyph_positions hb_buffer_has_positions -hb_buffer_get_invisible_glyph hb_buffer_set_invisible_glyph -hb_buffer_get_not_found_glyph +hb_buffer_get_invisible_glyph hb_buffer_set_not_found_glyph +hb_buffer_get_not_found_glyph +hb_buffer_set_not_found_variation_selector_glyph +hb_buffer_get_not_found_variation_selector_glyph hb_buffer_set_replacement_codepoint hb_buffer_get_replacement_codepoint +hb_buffer_set_random_state +hb_buffer_get_random_state hb_buffer_normalize_glyphs hb_buffer_reverse hb_buffer_reverse_range @@ -106,9 +103,11 @@ hb_segment_properties_equal hb_segment_properties_hash hb_segment_properties_overlay hb_buffer_diff +hb_buffer_message_func_t hb_buffer_set_message_func +HB_SEGMENT_PROPERTIES_DEFAULT +HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT hb_buffer_t -hb_glyph_info_get_glyph_flags hb_glyph_info_t hb_glyph_flags_t hb_glyph_position_t @@ -119,18 +118,25 @@ hb_segment_properties_t hb_buffer_serialize_format_t hb_buffer_serialize_flags_t hb_buffer_diff_flags_t -hb_buffer_message_func_t
hb-common +HB_TAG +HB_UNTAG hb_tag_from_string hb_tag_to_string hb_direction_from_string hb_direction_to_string +HB_DIRECTION_REVERSE +HB_DIRECTION_IS_BACKWARD +HB_DIRECTION_IS_FORWARD +HB_DIRECTION_IS_HORIZONTAL +HB_DIRECTION_IS_VALID +HB_DIRECTION_IS_VERTICAL hb_script_from_iso15924_tag -hb_script_from_string hb_script_to_iso15924_tag +hb_script_from_string hb_script_get_horizontal_direction hb_language_from_string hb_language_to_string @@ -142,6 +148,7 @@ hb_variation_from_string hb_variation_to_string hb_bool_t hb_codepoint_t +HB_CODEPOINT_INVALID hb_destroy_func_t hb_direction_t hb_language_t @@ -152,17 +159,9 @@ hb_position_t hb_tag_t hb_script_t hb_user_data_key_t -HB_TAG HB_TAG_NONE HB_TAG_MAX HB_TAG_MAX_SIGNED -HB_UNTAG -HB_DIRECTION_REVERSE -HB_DIRECTION_IS_BACKWARD -HB_DIRECTION_IS_FORWARD -HB_DIRECTION_IS_HORIZONTAL -HB_DIRECTION_IS_VALID -HB_DIRECTION_IS_VERTICAL HB_LANGUAGE_INVALID HB_FEATURE_GLOBAL_END HB_FEATURE_GLOBAL_START @@ -179,20 +178,40 @@ uint16_t uint32_t uint64_t uint8_t - HB_EXTERN HB_DEPRECATED HB_DEPRECATED_FOR + +HB_H_IN +HB_OT_H_IN +HB_AAT_H_IN +
+ +
+hb-features +HB_HAS_CAIRO +HB_HAS_CORETEXT +HB_HAS_DIRECTWRITE +HB_HAS_FREETYPE +HB_HAS_GDI +HB_HAS_GLIB +HB_HAS_GOBJECT +HB_HAS_GRAPHITE +HB_HAS_ICU +HB_HAS_UNISCRIBE +HB_HAS_WASM
hb-draw -hb_draw_funcs_t hb_draw_funcs_create -hb_draw_funcs_destroy +hb_draw_funcs_get_empty hb_draw_funcs_reference -hb_draw_funcs_is_immutable +hb_draw_funcs_destroy +hb_draw_funcs_set_user_data +hb_draw_funcs_get_user_data hb_draw_funcs_make_immutable +hb_draw_funcs_is_immutable hb_draw_move_to_func_t hb_draw_funcs_set_move_to_func hb_draw_line_to_func_t @@ -203,13 +222,82 @@ hb_draw_cubic_to_func_t hb_draw_funcs_set_cubic_to_func hb_draw_close_path_func_t hb_draw_funcs_set_close_path_func -hb_draw_state_t -HB_DRAW_STATE_DEFAULT hb_draw_move_to hb_draw_line_to hb_draw_quadratic_to hb_draw_cubic_to hb_draw_close_path +HB_DRAW_STATE_DEFAULT +hb_draw_funcs_t +hb_draw_state_t +
+ +
+hb-paint +hb_paint_funcs_t +hb_paint_funcs_create +hb_paint_funcs_get_empty +hb_paint_funcs_reference +hb_paint_funcs_destroy +hb_paint_funcs_set_user_data +hb_paint_funcs_get_user_data +hb_paint_funcs_make_immutable +hb_paint_funcs_is_immutable + +hb_paint_push_transform_func_t +hb_paint_funcs_set_push_transform_func +hb_paint_pop_transform_func_t +hb_paint_funcs_set_pop_transform_func +hb_paint_color_glyph_func_t +hb_paint_funcs_set_color_glyph_func +hb_paint_push_clip_glyph_func_t +hb_paint_funcs_set_push_clip_glyph_func +hb_paint_push_clip_rectangle_func_t +hb_paint_funcs_set_push_clip_rectangle_func +hb_paint_pop_clip_func_t +hb_paint_funcs_set_pop_clip_func +hb_paint_color_func_t +hb_paint_funcs_set_color_func +HB_PAINT_IMAGE_FORMAT_PNG +HB_PAINT_IMAGE_FORMAT_SVG +HB_PAINT_IMAGE_FORMAT_BGRA +hb_paint_image_func_t +hb_paint_funcs_set_image_func +hb_color_line_t +hb_color_stop_t +hb_color_line_get_color_stops_func_t +hb_color_line_get_color_stops +hb_paint_extend_t +hb_color_line_get_extend_func_t +hb_color_line_get_extend +hb_paint_linear_gradient_func_t +hb_paint_funcs_set_linear_gradient_func +hb_paint_radial_gradient_func_t +hb_paint_funcs_set_radial_gradient_func +hb_paint_sweep_gradient_func_t +hb_paint_funcs_set_sweep_gradient_func +hb_paint_composite_mode_t +hb_paint_push_group_func_t +hb_paint_funcs_set_push_group_func +hb_paint_pop_group_func_t +hb_paint_funcs_set_pop_group_func +hb_paint_custom_palette_color_func_t +hb_paint_funcs_set_custom_palette_color_func + +hb_paint_push_transform +hb_paint_pop_transform +hb_paint_color_glyph +hb_paint_push_clip_glyph +hb_paint_push_clip_rectangle +hb_paint_pop_clip +hb_paint_color +hb_paint_image +hb_paint_linear_gradient +hb_paint_radial_gradient +hb_paint_sweep_gradient +hb_paint_push_group +hb_paint_pop_group +hb_paint_custom_palette_color
@@ -236,9 +324,14 @@ HB_UNICODE_MAX_DECOMPOSITION_LEN hb_unicode_decompose_compatibility_func_t hb_unicode_decompose_compatibility hb_unicode_funcs_set_decompose_compatibility_func +HB_UNICODE_COMBINING_CLASS_CCC133 hb_font_funcs_set_glyph_v_kerning_func +hb_font_get_glyph_shape +hb_font_get_glyph_shape_func_t +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
@@ -247,9 +340,11 @@ HB_CORETEXT_TAG_KERX HB_CORETEXT_TAG_MORT HB_CORETEXT_TAG_MORX hb_coretext_face_create +hb_coretext_face_create_from_file_or_fail hb_coretext_font_create hb_coretext_face_get_cg_font hb_coretext_font_get_ct_font +hb_coretext_font_set_funcs
@@ -263,24 +358,30 @@ hb_directwrite_face_get_font_face hb_face_count hb_face_t hb_face_create +hb_face_create_or_fail +hb_face_create_from_file_or_fail +hb_reference_table_func_t hb_face_create_for_tables -hb_face_destroy hb_face_get_empty +hb_face_reference +hb_face_destroy +hb_face_set_user_data +hb_face_get_user_data +hb_face_make_immutable +hb_face_is_immutable +hb_get_table_tags_func_t +hb_face_set_get_table_tags_func hb_face_get_table_tags +hb_face_set_glyph_count hb_face_get_glyph_count +hb_face_set_index hb_face_get_index +hb_face_set_upem hb_face_get_upem -hb_face_get_user_data -hb_face_is_immutable -hb_face_make_immutable -hb_face_reference hb_face_reference_blob hb_face_reference_table -hb_face_set_glyph_count -hb_face_set_index -hb_face_set_upem -hb_face_set_user_data hb_face_collect_unicodes +hb_face_collect_nominal_glyph_mapping hb_face_collect_variation_selectors hb_face_collect_variation_unicodes hb_face_builder_create @@ -293,113 +394,120 @@ hb_face_builder_sort_tables hb_font_add_glyph_origin_for_direction hb_font_create hb_font_create_sub_font -hb_font_destroy -hb_font_funcs_create -hb_font_funcs_destroy -hb_font_funcs_get_empty -hb_font_funcs_get_user_data -hb_font_funcs_is_immutable -hb_font_funcs_make_immutable -hb_font_funcs_reference -hb_font_funcs_set_glyph_contour_point_func -hb_font_funcs_set_glyph_extents_func -hb_font_funcs_set_glyph_from_name_func -hb_font_funcs_set_glyph_h_advance_func -hb_font_funcs_set_glyph_h_advances_func -hb_font_funcs_set_glyph_h_kerning_func -hb_font_funcs_set_glyph_h_origin_func -hb_font_funcs_set_glyph_name_func -hb_font_funcs_set_glyph_shape_func -hb_font_funcs_set_glyph_v_advance_func -hb_font_funcs_set_glyph_v_advances_func -hb_font_funcs_set_glyph_v_origin_func -hb_font_funcs_set_nominal_glyph_func -hb_font_funcs_set_nominal_glyphs_func -hb_font_funcs_set_user_data -hb_font_funcs_set_variation_glyph_func -hb_font_funcs_t hb_font_get_empty +hb_font_reference +hb_font_destroy +hb_font_set_user_data +hb_font_get_user_data +hb_font_make_immutable +hb_font_is_immutable +hb_font_set_face hb_font_get_face hb_font_get_glyph hb_font_get_glyph_advance_for_direction -hb_font_get_glyph_advance_func_t hb_font_get_glyph_advances_for_direction -hb_font_get_glyph_advances_func_t hb_font_get_glyph_contour_point hb_font_get_glyph_contour_point_for_origin -hb_font_get_glyph_contour_point_func_t hb_font_get_glyph_extents hb_font_get_glyph_extents_for_origin -hb_font_get_glyph_extents_func_t hb_font_get_glyph_from_name -hb_font_get_glyph_from_name_func_t hb_font_get_glyph_h_advance -hb_font_get_glyph_h_advance_func_t +hb_font_get_glyph_v_advance hb_font_get_glyph_h_advances -hb_font_get_glyph_h_advances_func_t +hb_font_get_glyph_v_advances hb_font_get_glyph_h_kerning -hb_font_get_glyph_h_kerning_func_t -hb_font_get_glyph_h_origin -hb_font_get_glyph_h_origin_func_t hb_font_get_glyph_kerning_for_direction -hb_font_get_glyph_kerning_func_t -hb_font_get_glyph_name -hb_font_get_glyph_name_func_t -hb_font_get_glyph_origin_for_direction -hb_font_get_glyph_origin_func_t -hb_font_get_glyph_shape -hb_font_get_glyph_shape_func_t -hb_font_get_glyph_v_advance -hb_font_get_glyph_v_advance_func_t -hb_font_get_glyph_v_advances -hb_font_get_glyph_v_advances_func_t +hb_font_get_glyph_h_origin hb_font_get_glyph_v_origin -hb_font_get_glyph_v_origin_func_t +hb_font_get_glyph_origin_for_direction +hb_font_get_glyph_name +hb_font_draw_glyph +hb_font_paint_glyph hb_font_get_nominal_glyph -hb_font_get_nominal_glyph_func_t hb_font_get_nominal_glyphs -hb_font_get_nominal_glyphs_func_t +hb_font_get_variation_glyph +hb_font_set_parent hb_font_get_parent +hb_font_set_ppem hb_font_get_ppem +hb_font_set_ptem hb_font_get_ptem +hb_font_set_scale hb_font_get_scale +hb_font_get_synthetic_bold +hb_font_set_synthetic_bold +hb_font_set_synthetic_slant hb_font_get_synthetic_slant -hb_font_get_user_data -hb_font_get_variation_glyph -hb_font_get_variation_glyph_func_t +hb_font_set_variations +hb_font_set_variation +HB_FONT_NO_VAR_NAMED_INSTANCE +hb_font_set_var_named_instance +hb_font_get_var_named_instance +hb_font_set_var_coords_design hb_font_get_var_coords_design +hb_font_set_var_coords_normalized hb_font_get_var_coords_normalized hb_font_glyph_from_string hb_font_glyph_to_string -hb_font_is_immutable -hb_font_make_immutable hb_font_get_serial hb_font_changed -hb_font_reference -hb_font_set_face hb_font_set_funcs hb_font_set_funcs_data -hb_font_set_parent -hb_font_set_ppem -hb_font_set_ptem -hb_font_set_scale -hb_font_set_synthetic_slant -hb_font_set_user_data -hb_font_set_variations -hb_font_set_var_coords_design -hb_font_set_var_coords_normalized -hb_font_set_var_named_instance hb_font_subtract_glyph_origin_for_direction +hb_font_funcs_create +hb_font_funcs_get_empty +hb_font_funcs_reference +hb_font_funcs_destroy +hb_font_funcs_set_user_data +hb_font_funcs_get_user_data +hb_font_funcs_make_immutable +hb_font_funcs_is_immutable +hb_font_get_glyph_contour_point_func_t +hb_font_funcs_set_glyph_contour_point_func +hb_font_get_glyph_extents_func_t +hb_font_funcs_set_glyph_extents_func +hb_font_get_glyph_from_name_func_t +hb_font_funcs_set_glyph_from_name_func +hb_font_get_glyph_advance_func_t +hb_font_get_glyph_h_advance_func_t +hb_font_funcs_set_glyph_h_advance_func +hb_font_get_glyph_v_advance_func_t +hb_font_funcs_set_glyph_v_advance_func +hb_font_get_glyph_advances_func_t +hb_font_get_glyph_h_advances_func_t +hb_font_funcs_set_glyph_h_advances_func +hb_font_get_glyph_v_advances_func_t +hb_font_funcs_set_glyph_v_advances_func +hb_font_get_glyph_kerning_func_t +hb_font_get_glyph_h_kerning_func_t +hb_font_funcs_set_glyph_h_kerning_func +hb_font_get_glyph_origin_func_t +hb_font_get_glyph_h_origin_func_t +hb_font_funcs_set_glyph_h_origin_func +hb_font_get_glyph_v_origin_func_t +hb_font_funcs_set_glyph_v_origin_func +hb_font_get_glyph_name_func_t +hb_font_funcs_set_glyph_name_func +hb_font_draw_glyph_func_t +hb_font_funcs_set_draw_glyph_func +hb_font_paint_glyph_func_t +hb_font_funcs_set_paint_glyph_func +hb_font_get_nominal_glyph_func_t +hb_font_funcs_set_nominal_glyph_func +hb_font_get_nominal_glyphs_func_t +hb_font_funcs_set_nominal_glyphs_func +hb_font_get_variation_glyph_func_t +hb_font_funcs_set_variation_glyph_func +hb_font_funcs_t hb_font_t -hb_reference_table_func_t -hb_font_funcs_set_font_h_extents_func -hb_font_funcs_set_font_v_extents_func -hb_font_get_extents_for_direction hb_font_get_font_extents_func_t hb_font_get_font_h_extents_func_t +hb_font_funcs_set_font_h_extents_func hb_font_get_font_v_extents_func_t +hb_font_funcs_set_font_v_extents_func hb_font_get_h_extents hb_font_get_v_extents +hb_font_get_extents_for_direction hb_font_extents_t hb_glyph_extents_t
@@ -409,6 +517,7 @@ hb_glyph_extents_t hb_ft_face_create hb_ft_face_create_cached hb_ft_face_create_referenced +hb_ft_face_create_from_file_or_fail hb_ft_font_create hb_ft_font_create_referenced hb_ft_font_changed @@ -450,49 +559,55 @@ hb_icu_script_to_script
hb-map -HB_MAP_VALUE_INVALID +hb_map_create hb_map_allocation_successful -hb_map_clear hb_map_copy -hb_map_create -hb_map_del +hb_map_clear +hb_map_get_empty +hb_map_reference hb_map_destroy +hb_map_set_user_data +hb_map_get_user_data +hb_map_set hb_map_get -hb_map_get_empty +hb_map_del +hb_map_has hb_map_get_population +hb_map_is_empty hb_map_is_equal -hb_map_get_user_data -hb_map_has hb_map_hash -hb_map_is_empty -hb_map_reference -hb_map_set -hb_map_set_user_data +hb_map_update +hb_map_next +hb_map_keys +hb_map_values +HB_MAP_VALUE_INVALID hb_map_t
hb-ot-color -hb_color_t HB_COLOR hb_color_get_alpha hb_color_get_blue hb_color_get_green hb_color_get_red -hb_ot_color_glyph_get_layers -hb_ot_color_glyph_reference_png -hb_ot_color_glyph_reference_svg hb_ot_color_has_layers +hb_ot_color_glyph_get_layers hb_ot_color_has_palettes +hb_ot_color_palette_get_count +hb_ot_color_palette_get_colors +hb_ot_color_palette_get_flags +hb_ot_color_palette_get_name_id +hb_ot_color_palette_color_get_name_id +hb_ot_color_has_paint +hb_ot_color_glyph_has_paint hb_ot_color_has_png +hb_ot_color_glyph_reference_png hb_ot_color_has_svg +hb_ot_color_glyph_reference_svg +hb_color_t hb_ot_color_layer_t -hb_ot_color_palette_color_get_name_id hb_ot_color_palette_flags_t -hb_ot_color_palette_get_colors -hb_ot_color_palette_get_count -hb_ot_color_palette_get_flags -hb_ot_color_palette_get_name_id
@@ -502,50 +617,40 @@ hb_ot_font_set_funcs
hb-ot-name -hb_ot_name_id_t -HB_OT_NAME_ID_INVALID -hb_ot_name_entry_t hb_ot_name_list_names hb_ot_name_get_utf16 hb_ot_name_get_utf32 hb_ot_name_get_utf8 +hb_ot_name_id_t +hb_ot_name_id_predefined_t +hb_ot_name_entry_t
hb-ot-layout -HB_OT_MAX_TAGS_PER_LANGUAGE -HB_OT_MAX_TAGS_PER_SCRIPT -HB_OT_TAG_DEFAULT_LANGUAGE -HB_OT_TAG_DEFAULT_SCRIPT hb_ot_tag_to_language hb_ot_tag_to_script hb_ot_tags_from_script_and_language hb_ot_tags_to_script_and_language -HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX -HB_OT_LAYOUT_NO_FEATURE_INDEX -HB_OT_LAYOUT_NO_SCRIPT_INDEX -HB_OT_LAYOUT_NO_VARIATIONS_INDEX -HB_OT_TAG_BASE -HB_OT_TAG_GDEF -HB_OT_TAG_GPOS -HB_OT_TAG_GSUB -HB_OT_TAG_JSTF -hb_ot_layout_baseline_tag_t hb_ot_layout_collect_lookups hb_ot_layout_collect_features +hb_ot_layout_collect_features_map hb_ot_layout_feature_get_characters hb_ot_layout_feature_get_lookups hb_ot_layout_feature_get_name_ids hb_ot_layout_feature_with_variations_get_lookups hb_ot_layout_get_attach_points +hb_ot_layout_get_font_extents +hb_ot_layout_get_font_extents2 hb_ot_layout_get_horizontal_baseline_tag_for_script hb_ot_layout_get_baseline +hb_ot_layout_get_baseline2 hb_ot_layout_get_baseline_with_fallback +hb_ot_layout_get_baseline_with_fallback2 hb_ot_layout_get_glyph_class hb_ot_layout_get_glyphs_in_class hb_ot_layout_get_ligature_carets hb_ot_layout_get_size_params -hb_ot_layout_glyph_class_t hb_ot_layout_has_glyph_classes hb_ot_layout_has_positioning hb_ot_layout_has_substitution @@ -562,6 +667,7 @@ hb_ot_layout_lookup_would_substitute hb_ot_layout_script_find_language hb_ot_layout_script_get_language_tags hb_ot_layout_script_select_language +hb_ot_layout_script_select_language2 hb_ot_layout_table_find_feature_variations hb_ot_layout_table_get_feature_tags hb_ot_layout_table_get_script_tags @@ -569,18 +675,25 @@ hb_ot_layout_table_get_lookup_count hb_ot_layout_table_select_script hb_ot_shape_plan_collect_lookups hb_ot_layout_language_get_required_feature_index +HB_OT_MAX_TAGS_PER_LANGUAGE +HB_OT_MAX_TAGS_PER_SCRIPT +HB_OT_TAG_DEFAULT_LANGUAGE +HB_OT_TAG_DEFAULT_SCRIPT +HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX +HB_OT_LAYOUT_NO_FEATURE_INDEX +HB_OT_LAYOUT_NO_SCRIPT_INDEX +HB_OT_LAYOUT_NO_VARIATIONS_INDEX +HB_OT_TAG_BASE +HB_OT_TAG_GDEF +HB_OT_TAG_GPOS +HB_OT_TAG_GSUB +HB_OT_TAG_JSTF +hb_ot_layout_baseline_tag_t +hb_ot_layout_glyph_class_t
hb-ot-math -HB_OT_TAG_MATH -HB_OT_TAG_MATH_SCRIPT -hb_ot_math_constant_t -hb_ot_math_kern_t -hb_ot_math_kern_entry_t -hb_ot_math_glyph_variant_t -hb_ot_math_glyph_part_flags_t -hb_ot_math_glyph_part_t hb_ot_math_has_data hb_ot_math_get_constant hb_ot_math_get_glyph_italics_correction @@ -591,23 +704,31 @@ hb_ot_math_is_glyph_extended_shape hb_ot_math_get_glyph_variants hb_ot_math_get_min_connector_overlap hb_ot_math_get_glyph_assembly +HB_OT_TAG_MATH +HB_OT_TAG_MATH_SCRIPT +hb_ot_math_constant_t +hb_ot_math_kern_t +hb_ot_math_kern_entry_t +hb_ot_math_glyph_variant_t +hb_ot_math_glyph_part_flags_t +hb_ot_math_glyph_part_t
hb-ot-meta -hb_ot_meta_tag_t hb_ot_meta_get_entry_tags hb_ot_meta_reference_entry +hb_ot_meta_tag_t
hb-ot-metrics -hb_ot_metrics_tag_t hb_ot_metrics_get_position hb_ot_metrics_get_position_with_fallback hb_ot_metrics_get_variation hb_ot_metrics_get_x_variation hb_ot_metrics_get_y_variation +hb_ot_metrics_tag_t
@@ -617,14 +738,7 @@ hb_ot_shape_glyphs_closure
hb-ot-var -HB_OT_TAG_VAR_AXIS_ITALIC -HB_OT_TAG_VAR_AXIS_OPTICAL_SIZE -HB_OT_TAG_VAR_AXIS_SLANT -HB_OT_TAG_VAR_AXIS_WEIGHT -HB_OT_TAG_VAR_AXIS_WIDTH hb_ot_var_has_data -hb_ot_var_axis_flags_t -hb_ot_var_axis_info_t hb_ot_var_find_axis_info hb_ot_var_get_axis_count hb_ot_var_get_axis_infos @@ -634,31 +748,44 @@ hb_ot_var_named_instance_get_postscript_name_id hb_ot_var_named_instance_get_design_coords hb_ot_var_normalize_variations hb_ot_var_normalize_coords +HB_OT_TAG_VAR_AXIS_ITALIC +HB_OT_TAG_VAR_AXIS_OPTICAL_SIZE +HB_OT_TAG_VAR_AXIS_SLANT +HB_OT_TAG_VAR_AXIS_WEIGHT +HB_OT_TAG_VAR_AXIS_WIDTH +hb_ot_var_axis_flags_t +hb_ot_var_axis_info_t
hb-set -HB_SET_VALUE_INVALID -hb_set_add -hb_set_add_range -hb_set_add_sorted_array +hb_set_create hb_set_allocation_successful hb_set_copy +hb_set_get_empty +hb_set_reference +hb_set_destroy +hb_set_set_user_data +hb_set_get_user_data hb_set_clear -hb_set_create +hb_set_set +hb_set_has +hb_set_add +hb_set_add_range +hb_set_add_sorted_array hb_set_del hb_set_del_range -hb_set_destroy -hb_set_get_empty hb_set_get_max hb_set_get_min hb_set_get_population -hb_set_get_user_data -hb_set_has +hb_set_is_empty hb_set_hash +hb_set_subtract hb_set_intersect +hb_set_union +hb_set_symmetric_difference hb_set_invert -hb_set_is_empty +hb_set_is_inverted hb_set_is_equal hb_set_is_subset hb_set_next @@ -666,19 +793,15 @@ hb_set_next_range hb_set_next_many hb_set_previous hb_set_previous_range -hb_set_reference -hb_set_set -hb_set_set_user_data -hb_set_subtract -hb_set_symmetric_difference +HB_SET_VALUE_INVALID hb_set_t -hb_set_union
hb-shape hb_shape hb_shape_full +hb_shape_justify hb_shape_list_shapers
@@ -688,50 +811,50 @@ hb_shape_plan_create hb_shape_plan_create_cached hb_shape_plan_create2 hb_shape_plan_create_cached2 -hb_shape_plan_destroy -hb_shape_plan_execute hb_shape_plan_get_empty -hb_shape_plan_get_shaper -hb_shape_plan_get_user_data hb_shape_plan_reference +hb_shape_plan_destroy hb_shape_plan_set_user_data +hb_shape_plan_get_user_data +hb_shape_plan_execute +hb_shape_plan_get_shaper hb_shape_plan_t
hb-unicode -HB_UNICODE_MAX +hb_unicode_general_category hb_unicode_combining_class -hb_unicode_combining_class_func_t -hb_unicode_combining_class_t +hb_unicode_mirroring +hb_unicode_script hb_unicode_compose -hb_unicode_compose_func_t hb_unicode_decompose -hb_unicode_decompose_func_t hb_unicode_funcs_create -hb_unicode_funcs_destroy -hb_unicode_funcs_get_default hb_unicode_funcs_get_empty -hb_unicode_funcs_get_parent +hb_unicode_funcs_reference +hb_unicode_funcs_destroy +hb_unicode_funcs_set_user_data hb_unicode_funcs_get_user_data -hb_unicode_funcs_is_immutable hb_unicode_funcs_make_immutable -hb_unicode_funcs_reference -hb_unicode_funcs_set_combining_class_func -hb_unicode_funcs_set_compose_func -hb_unicode_funcs_set_decompose_func +hb_unicode_funcs_is_immutable +hb_unicode_funcs_get_default +hb_unicode_funcs_get_parent +hb_unicode_general_category_func_t hb_unicode_funcs_set_general_category_func +hb_unicode_combining_class_func_t +hb_unicode_funcs_set_combining_class_func +hb_unicode_mirroring_func_t hb_unicode_funcs_set_mirroring_func +hb_unicode_script_func_t hb_unicode_funcs_set_script_func -hb_unicode_funcs_set_user_data -hb_unicode_funcs_t -hb_unicode_general_category -hb_unicode_general_category_func_t +hb_unicode_compose_func_t +hb_unicode_funcs_set_compose_func +hb_unicode_decompose_func_t +hb_unicode_funcs_set_decompose_func +HB_UNICODE_MAX +hb_unicode_combining_class_t hb_unicode_general_category_t -hb_unicode_mirroring -hb_unicode_mirroring_func_t -hb_unicode_script -hb_unicode_script_func_t +hb_unicode_funcs_t
@@ -743,13 +866,13 @@ hb_uniscribe_font_get_logfontw
hb-version HB_VERSION_ATLEAST +hb_version +hb_version_atleast +hb_version_string HB_VERSION_MAJOR HB_VERSION_MICRO HB_VERSION_MINOR HB_VERSION_STRING -hb_version -hb_version_atleast -hb_version_string
@@ -760,20 +883,23 @@ hb_style_get_value
hb-subset -hb_subset_flags_t -hb_subset_input_t -hb_subset_sets_t -hb_subset_plan_t hb_subset_input_create_or_fail hb_subset_input_reference hb_subset_input_destroy hb_subset_input_set_user_data hb_subset_input_get_user_data -hb_subset_input_get_flags +hb_subset_input_keep_everything hb_subset_input_set_flags +hb_subset_input_get_flags hb_subset_input_unicode_set hb_subset_input_glyph_set hb_subset_input_set +hb_subset_input_old_to_new_glyph_mapping +hb_subset_input_pin_all_axes_to_default +hb_subset_input_pin_axis_location +hb_subset_input_pin_axis_to_default +hb_subset_input_get_axis_range +hb_subset_input_set_axis_range hb_subset_or_fail hb_subset_plan_create_or_fail hb_subset_plan_reference @@ -784,11 +910,28 @@ hb_subset_plan_execute_or_fail hb_subset_plan_unicode_to_old_glyph_mapping hb_subset_plan_new_to_old_glyph_mapping hb_subset_plan_old_to_new_glyph_mapping +hb_subset_preprocess +hb_subset_flags_t +hb_subset_input_t +hb_subset_sets_t +hb_subset_plan_t hb_link_t hb_object_t hb_subset_repack_or_fail -hb_subset_preprocess -hb_subset_input_pin_axis_location -hb_subset_input_pin_axis_to_default +hb_subset_input_override_name_table +
+ +
+hb-cairo +hb_cairo_font_face_create_for_font +hb_cairo_font_face_get_font +hb_cairo_font_face_create_for_face +hb_cairo_font_face_get_face +hb_cairo_font_init_func_t +hb_cairo_font_face_set_font_init_func +hb_cairo_scaled_font_get_font +hb_cairo_font_face_set_scale_factor +hb_cairo_font_face_get_scale_factor +hb_cairo_glyphs_from_buffer
diff --git a/libs/harfbuzz/docs/meson.build b/libs/harfbuzz/docs/meson.build index 9da1fd564..45ca93ad3 100644 --- a/libs/harfbuzz/docs/meson.build +++ b/libs/harfbuzz/docs/meson.build @@ -1,8 +1,3 @@ -if build_machine.system() == 'windows' - message('Skipping gtk-doc while building on Windows') - subdir_done() -endif - if not find_program('gtkdoc-scan', required: get_option('docs')).found() message('Not building documentation as gtk-doc was not found') subdir_done() @@ -41,10 +36,12 @@ html_images = [ ] ignore_headers = [ + 'hb-features.h', 'hb-gobject.h', 'hb-gobject-enums.h', 'hb-gobject-enums-tmp.h', 'hb-gobject-structs.h', + 'hb-wasm-api.h', ] gnome.gtkdoc('harfbuzz', @@ -53,7 +50,7 @@ gnome.gtkdoc('harfbuzz', meson.current_build_dir() / '..' / 'src', ], scan_args: ['--deprecated-guards=HB_DISABLE_DEPRECATED', - '--ignore-decorators=HB_EXTERN|HB_DEPRECATED', + '--ignore-decorators=HB_EXTERN|HB_DEPRECATED|HB_DEPRECATED_FOR()', ], mkdb_args: ['--source-suffixes=h,cc', '--xml-mode', @@ -63,4 +60,6 @@ gnome.gtkdoc('harfbuzz', html_assets: html_images, ignore_headers: ignore_headers, dependencies: [libharfbuzz_dep], - install: true) + install: true, + check: get_option('doc_tests'), +) diff --git a/libs/harfbuzz/docs/serializer.md b/libs/harfbuzz/docs/serializer.md index 0efda8055..7954ac090 100644 --- a/libs/harfbuzz/docs/serializer.md +++ b/libs/harfbuzz/docs/serializer.md @@ -73,7 +73,7 @@ using object ids. The serialize context maintains a list of links between objects. Each link records the parent object id, the child object id, the position of the offset field within the parent object, and the width of the offset. -Links are always added to the current in progress object and you can only link too +Links are always added to the current in progress object and you can only link to objects that have been packed and thus have an ID. ### Object De-duplication diff --git a/libs/harfbuzz/docs/subset-preprocessing.md b/libs/harfbuzz/docs/subset-preprocessing.md new file mode 100644 index 000000000..637da2865 --- /dev/null +++ b/libs/harfbuzz/docs/subset-preprocessing.md @@ -0,0 +1,228 @@ +# Introduction + +Subset preprocessing is a mechanism which can significantly speed up font subsetting operations. +It works by prepopulating datastructures from the source font which can be used in later subsetting +operations to more quickly produce the subset. Preprocessing is useful in cases where multiple subsets +will be cut from the same source font. + +# Usage + +```c++ +hb_face_t* preprocessed = hb_subset_preprocess (source_face); + +... + +hb_face_t* subset = hb_subset_or_fail (preprocessed, subset_input); +``` + +# Additional Details + +* A subset produced from a preprocessed face should be identical to a subset produced from only the + original face. The preprocessor does not change the functionality of the subsetter, just speeds + things up. + +* The preprocessing operation may take longer than the time it takes to produce a subset from the + source font. Thus the main performance gains are made when a preprocessed face is reused for + multiple subsetting operations. + +* Currently the largest performance gains are seen when using a preprocessed face for CFF subsetting. + +* The preprocessed face may contain references to the memory backing the source face. If this memory + is fully owned by a harfbuzz hb_blob_t* then it will automatically be kept alive for the lifetime + of the preprocessed face. However, if this memory is not fully owned by a harfbuzz hb_blob_t* then + it is necessary to ensure that the memory is kept alive for the lifetime of the preprocessed face. + + +# Performance Improvements + +Here is the performance difference of producing a subset with a preprocessed face vs producing +a subset with the source face: + +Benchmark | Delta Time (%) +----------|----------------- +BM_subset/subset_glyphs/Roboto-Regular.ttf/10_median|-56% +BM_subset/subset_glyphs/Roboto-Regular.ttf/64_median|-33% +BM_subset/subset_glyphs/Roboto-Regular.ttf/512_median|-28% +BM_subset/subset_glyphs/Roboto-Regular.ttf/1000_median|-11% +BM_subset/subset_glyphs/Roboto-Regular.ttf/nohinting/10_median|-56% +BM_subset/subset_glyphs/Roboto-Regular.ttf/nohinting/64_median|-33% +BM_subset/subset_glyphs/Roboto-Regular.ttf/nohinting/512_median|-21% +BM_subset/subset_glyphs/Roboto-Regular.ttf/nohinting/1000_median|-9% +BM_subset/subset_glyphs/Amiri-Regular.ttf/10_median|-67% +BM_subset/subset_glyphs/Amiri-Regular.ttf/64_median|-48% +BM_subset/subset_glyphs/Amiri-Regular.ttf/512_median|-21% +BM_subset/subset_glyphs/Amiri-Regular.ttf/4096_median|-9% +BM_subset/subset_glyphs/Amiri-Regular.ttf/nohinting/10_median|-66% +BM_subset/subset_glyphs/Amiri-Regular.ttf/nohinting/64_median|-50% +BM_subset/subset_glyphs/Amiri-Regular.ttf/nohinting/512_median|-8% +BM_subset/subset_glyphs/Amiri-Regular.ttf/nohinting/4096_median|-9% +BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/10_median|-85% +BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/64_median|-71% +BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/512_median|-3% +BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/1400_median|4% +BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/nohinting/10_median|-84% +BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/nohinting/64_median|-72% +BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/nohinting/512_median|0% +BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/nohinting/1400_median|0% +BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/10_median|-30% +BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/64_median|-24% +BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/512_median|-3% +BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/1000_median|-3% +BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/nohinting/10_median|-30% +BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/nohinting/64_median|-24% +BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/nohinting/512_median|-3% +BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/nohinting/1000_median|-5% +BM_subset/subset_glyphs/Mplus1p-Regular.ttf/10_median|-96% +BM_subset/subset_glyphs/Mplus1p-Regular.ttf/64_median|-90% +BM_subset/subset_glyphs/Mplus1p-Regular.ttf/512_median|-74% +BM_subset/subset_glyphs/Mplus1p-Regular.ttf/4096_median|-25% +BM_subset/subset_glyphs/Mplus1p-Regular.ttf/10000_median|-23% +BM_subset/subset_glyphs/Mplus1p-Regular.ttf/nohinting/10_median|-95% +BM_subset/subset_glyphs/Mplus1p-Regular.ttf/nohinting/64_median|-90% +BM_subset/subset_glyphs/Mplus1p-Regular.ttf/nohinting/512_median|-73% +BM_subset/subset_glyphs/Mplus1p-Regular.ttf/nohinting/4096_median|-24% +BM_subset/subset_glyphs/Mplus1p-Regular.ttf/nohinting/10000_median|-11% +BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/10_median|-84% +BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/64_median|-77% +BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/512_median|-70% +BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/4096_median|-80% +BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/10000_median|-86% +BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/nohinting/10_median|-84% +BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/nohinting/64_median|-78% +BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/nohinting/512_median|-71% +BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/nohinting/4096_median|-86% +BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/nohinting/10000_median|-88% +BM_subset/subset_glyphs/SourceSansPro-Regular.otf/10_median|-59% +BM_subset/subset_glyphs/SourceSansPro-Regular.otf/64_median|-55% +BM_subset/subset_glyphs/SourceSansPro-Regular.otf/512_median|-67% +BM_subset/subset_glyphs/SourceSansPro-Regular.otf/2000_median|-68% +BM_subset/subset_glyphs/SourceSansPro-Regular.otf/nohinting/10_median|-60% +BM_subset/subset_glyphs/SourceSansPro-Regular.otf/nohinting/64_median|-58% +BM_subset/subset_glyphs/SourceSansPro-Regular.otf/nohinting/512_median|-72% +BM_subset/subset_glyphs/SourceSansPro-Regular.otf/nohinting/2000_median|-71% +BM_subset/subset_glyphs/AdobeVFPrototype.otf/10_median|-70% +BM_subset/subset_glyphs/AdobeVFPrototype.otf/64_median|-64% +BM_subset/subset_glyphs/AdobeVFPrototype.otf/300_median|-73% +BM_subset/subset_glyphs/AdobeVFPrototype.otf/nohinting/10_median|-71% +BM_subset/subset_glyphs/AdobeVFPrototype.otf/nohinting/64_median|-68% +BM_subset/subset_glyphs/AdobeVFPrototype.otf/nohinting/300_median|-72% +BM_subset/subset_glyphs/MPLUS1-Variable.ttf/10_median|-90% +BM_subset/subset_glyphs/MPLUS1-Variable.ttf/64_median|-82% +BM_subset/subset_glyphs/MPLUS1-Variable.ttf/512_median|-31% +BM_subset/subset_glyphs/MPLUS1-Variable.ttf/4096_median|-9% +BM_subset/subset_glyphs/MPLUS1-Variable.ttf/6000_median|-22% +BM_subset/subset_glyphs/MPLUS1-Variable.ttf/nohinting/10_median|-88% +BM_subset/subset_glyphs/MPLUS1-Variable.ttf/nohinting/64_median|-83% +BM_subset/subset_glyphs/MPLUS1-Variable.ttf/nohinting/512_median|-31% +BM_subset/subset_glyphs/MPLUS1-Variable.ttf/nohinting/4096_median|-16% +BM_subset/subset_glyphs/MPLUS1-Variable.ttf/nohinting/6000_median|-18% +BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/10_median|-44% +BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/64_median|-18% +BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/512_median|-2% +BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/900_median|-6% +BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/nohinting/10_median|-45% +BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/nohinting/64_median|-17% +BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/nohinting/512_median|-15% +BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/nohinting/900_median|-3% +BM_subset/subset_codepoints/Roboto-Regular.ttf/10_median|-20% +BM_subset/subset_codepoints/Roboto-Regular.ttf/64_median|-16% +BM_subset/subset_codepoints/Roboto-Regular.ttf/512_median|-12% +BM_subset/subset_codepoints/Roboto-Regular.ttf/1000_median|-10% +BM_subset/subset_codepoints/Roboto-Regular.ttf/nohinting/10_median|-24% +BM_subset/subset_codepoints/Roboto-Regular.ttf/nohinting/64_median|-14% +BM_subset/subset_codepoints/Roboto-Regular.ttf/nohinting/512_median|-15% +BM_subset/subset_codepoints/Roboto-Regular.ttf/nohinting/1000_median|-9% +BM_subset/subset_codepoints/Amiri-Regular.ttf/10_median|-51% +BM_subset/subset_codepoints/Amiri-Regular.ttf/64_median|-37% +BM_subset/subset_codepoints/Amiri-Regular.ttf/512_median|-12% +BM_subset/subset_codepoints/Amiri-Regular.ttf/4096_median|-1% +BM_subset/subset_codepoints/Amiri-Regular.ttf/nohinting/10_median|-49% +BM_subset/subset_codepoints/Amiri-Regular.ttf/nohinting/64_median|-35% +BM_subset/subset_codepoints/Amiri-Regular.ttf/nohinting/512_median|-6% +BM_subset/subset_codepoints/Amiri-Regular.ttf/nohinting/4096_median|-1% +BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/10_median|-82% +BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/64_median|-9% +BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/512_median|0% +BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/1400_median|0% +BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/nohinting/10_median|-82% +BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/nohinting/64_median|-13% +BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/nohinting/512_median|-3% +BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/nohinting/1400_median|2% +BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/10_median|-40% +BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/64_median|-26% +BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/512_median|-5% +BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/1000_median|3% +BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/nohinting/10_median|-43% +BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/nohinting/64_median|-24% +BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/nohinting/512_median|-2% +BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/nohinting/1000_median|2% +BM_subset/subset_codepoints/Mplus1p-Regular.ttf/10_median|-83% +BM_subset/subset_codepoints/Mplus1p-Regular.ttf/64_median|-67% +BM_subset/subset_codepoints/Mplus1p-Regular.ttf/512_median|-39% +BM_subset/subset_codepoints/Mplus1p-Regular.ttf/4096_median|-20% +BM_subset/subset_codepoints/Mplus1p-Regular.ttf/10000_median|-25% +BM_subset/subset_codepoints/Mplus1p-Regular.ttf/nohinting/10_median|-83% +BM_subset/subset_codepoints/Mplus1p-Regular.ttf/nohinting/64_median|-65% +BM_subset/subset_codepoints/Mplus1p-Regular.ttf/nohinting/512_median|-42% +BM_subset/subset_codepoints/Mplus1p-Regular.ttf/nohinting/4096_median|-34% +BM_subset/subset_codepoints/Mplus1p-Regular.ttf/nohinting/10000_median|-21% +BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/10_median|-69% +BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/64_median|-69% +BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/512_median|-70% +BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/4096_median|-84% +BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/10000_median|-83% +BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/10_median|-71% +BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/64_median|-68% +BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/512_median|-70% +BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/4096_median|-86% +BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/10000_median|-88% +BM_subset/subset_codepoints/SourceSansPro-Regular.otf/10_median|-45% +BM_subset/subset_codepoints/SourceSansPro-Regular.otf/64_median|-48% +BM_subset/subset_codepoints/SourceSansPro-Regular.otf/512_median|-57% +BM_subset/subset_codepoints/SourceSansPro-Regular.otf/2000_median|-66% +BM_subset/subset_codepoints/SourceSansPro-Regular.otf/nohinting/10_median|-43% +BM_subset/subset_codepoints/SourceSansPro-Regular.otf/nohinting/64_median|-50% +BM_subset/subset_codepoints/SourceSansPro-Regular.otf/nohinting/512_median|-63% +BM_subset/subset_codepoints/SourceSansPro-Regular.otf/nohinting/2000_median|-72% +BM_subset/subset_codepoints/AdobeVFPrototype.otf/10_median|-69% +BM_subset/subset_codepoints/AdobeVFPrototype.otf/64_median|-66% +BM_subset/subset_codepoints/AdobeVFPrototype.otf/300_median|-74% +BM_subset/subset_codepoints/AdobeVFPrototype.otf/nohinting/10_median|-70% +BM_subset/subset_codepoints/AdobeVFPrototype.otf/nohinting/64_median|-71% +BM_subset/subset_codepoints/AdobeVFPrototype.otf/nohinting/300_median|-75% +BM_subset/subset_codepoints/MPLUS1-Variable.ttf/10_median|-66% +BM_subset/subset_codepoints/MPLUS1-Variable.ttf/64_median|-46% +BM_subset/subset_codepoints/MPLUS1-Variable.ttf/512_median|-15% +BM_subset/subset_codepoints/MPLUS1-Variable.ttf/4096_median|-5% +BM_subset/subset_codepoints/MPLUS1-Variable.ttf/6000_median|-16% +BM_subset/subset_codepoints/MPLUS1-Variable.ttf/nohinting/10_median|-66% +BM_subset/subset_codepoints/MPLUS1-Variable.ttf/nohinting/64_median|-45% +BM_subset/subset_codepoints/MPLUS1-Variable.ttf/nohinting/512_median|-14% +BM_subset/subset_codepoints/MPLUS1-Variable.ttf/nohinting/4096_median|-11% +BM_subset/subset_codepoints/MPLUS1-Variable.ttf/nohinting/6000_median|-27% +BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/10_median|-38% +BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/64_median|-9% +BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/512_median|-3% +BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/900_median|-16% +BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/nohinting/10_median|-39% +BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/nohinting/64_median|-12% +BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/nohinting/512_median|-4% +BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/nohinting/900_median|-2% +BM_subset/instance/MPLUS1-Variable.ttf/10_median|-68% +BM_subset/instance/MPLUS1-Variable.ttf/64_median|-45% +BM_subset/instance/MPLUS1-Variable.ttf/512_median|-18% +BM_subset/instance/MPLUS1-Variable.ttf/4096_median|-2% +BM_subset/instance/MPLUS1-Variable.ttf/6000_median|4% +BM_subset/instance/MPLUS1-Variable.ttf/nohinting/10_median|-69% +BM_subset/instance/MPLUS1-Variable.ttf/nohinting/64_median|-46% +BM_subset/instance/MPLUS1-Variable.ttf/nohinting/512_median|-11% +BM_subset/instance/MPLUS1-Variable.ttf/nohinting/4096_median|4% +BM_subset/instance/MPLUS1-Variable.ttf/nohinting/6000_median|-5% +BM_subset/instance/RobotoFlex-Variable.ttf/10_median|-34% +BM_subset/instance/RobotoFlex-Variable.ttf/64_median|-12% +BM_subset/instance/RobotoFlex-Variable.ttf/512_median|6% +BM_subset/instance/RobotoFlex-Variable.ttf/900_median|-6% +BM_subset/instance/RobotoFlex-Variable.ttf/nohinting/10_median|-33% +BM_subset/instance/RobotoFlex-Variable.ttf/nohinting/64_median|-11% +BM_subset/instance/RobotoFlex-Variable.ttf/nohinting/512_median|3% +BM_subset/instance/RobotoFlex-Variable.ttf/nohinting/900_median|0% diff --git a/libs/harfbuzz/docs/usermanual-clusters.xml b/libs/harfbuzz/docs/usermanual-clusters.xml index 4f2825c0b..545afde89 100644 --- a/libs/harfbuzz/docs/usermanual-clusters.xml +++ b/libs/harfbuzz/docs/usermanual-clusters.xml @@ -182,8 +182,7 @@ - Level 0 is the default and - reproduces the behavior of the old HarfBuzz library. + Level 0 is the default. The distinguishing feature of level 0 behavior is that, at @@ -194,7 +193,7 @@ as well as the Zero Width Joiner and Zero Width Non-Joiner code points, are assigned the cluster value of the closest preceding code - point from different category. + point from different category. In essence, whenever a base character is followed by a mark @@ -206,6 +205,11 @@ url="https://www.unicode.org/reports/tr29/#Regex_Definitions">Unicode Technical Report 29. + + This cluster level is suitable for code that likes to use + HarfBuzz cluster values as an approximation of the Unicode + Grapheme Cluster Boundaries as well. + Client programs can specify level 0 behavior for a buffer by setting its cluster_level to @@ -220,13 +224,13 @@ implement backward compatibility with the old HarfBuzz. - Level 1 differs from level 0 by not merging the + Level 1 differs from level 0 by not merging the clusters of marks and other modifier code points with the preceding "base" code point's cluster. By preserving the separate cluster values of these marks and modifier code points, script shapers can perform additional operations - that might lead to improved results (for example, reordering - a sequence of marks). + that might lead to improved results (for example, coloring + mark glyphs differently than their base). Client programs can specify level 1 behavior for a buffer by @@ -242,7 +246,7 @@ This difference can be seen most clearly when HarfBuzz processes - ligature substitutions and glyph decompositions. In level 0 + ligature substitutions and glyph decompositions. In level 0 and level 1, ligatures and glyph decomposition both involve merging clusters; in level 2, neither of these operations triggers a merge. @@ -259,7 +263,7 @@ assign initial cluster values in a buffer by reusing the indices of the code points in the input text. This gives a sequence of cluster values that is monotonically increasing (for example, - 0,1,2,3,4). + 0,1,2,3,4). It is not required that the cluster values @@ -314,7 +318,7 @@
- +
A clustering example for levels 0 and 1 diff --git a/libs/harfbuzz/docs/usermanual-fonts-and-faces.xml b/libs/harfbuzz/docs/usermanual-fonts-and-faces.xml index abf5dc2b4..39233948b 100644 --- a/libs/harfbuzz/docs/usermanual-fonts-and-faces.xml +++ b/libs/harfbuzz/docs/usermanual-fonts-and-faces.xml @@ -55,7 +55,7 @@ shaping. The typeface must be set to a specific point size in order for some details (such as hinting) to work. In addition, if the font file in question is an OpenType Variable Font, then - you may need to specify one or variation-axis settings (or a + you may need to specify one or more variation-axis settings (or a named instance) in order to get the output you need. @@ -256,6 +256,18 @@ hb_font_get_glyph_from_name_func_t: returns the glyph index that corresponds to a given glyph name. + + + + + hb_font_draw_glyph_func_t: gets the outlines + of a glyph (by calling #hb_draw_funcs_t callbacks). + + + + + hb_font_paint_glyph_func_t: paints a glyph + (by calling #hb_paint_funcs_t callbacks). @@ -375,20 +387,6 @@
- - - - -
Working with OpenType Variable Fonts @@ -455,13 +453,66 @@ range actually implemented in the font's variation axis. After all, a font might only provide lighter-than-regular weights, and setting a heavier value on the wght axis will - not change that. + not change that. Once your variation settings are specified on your font object, however, shaping with a variable font is just like shaping a static font. + + In addition to providing the variation axes themselves, fonts may also + pre-define certain variation coordinates as named instances. HarfBuzz + makes these coordinates (and their associated names) available via + hb_ot_var_named_instance_get_design_coords() and + hb_ot_var_named_instance_get_subfamily_name_id(). + + + Applications should treat named instances like multiple independent, + static fonts. + +
+ +
+ Glyphs and rendering + + + The main purpose of HarfBuzz is shaping, which creates a list of positioned + glyphs as output. The remaining task for text layout is to convert this list + into rendered output. While HarfBuzz does not handle rasterization of glyphs + per se, it does have APIs that provide access to the font data that is needed + to perform this task. + + + Traditionally, the shapes of glyphs in scalable fonts are provided as quadratic + or cubic Beziér curves defining outlines to be filled. To obtain the outlines + for a glyph, call hb_font_draw_glyph() and pass a + hb_draw_funcs_t struct. The callbacks in that struct will be called + for each segment of the outline. Note that this API provides access to outlines + as they are defined in the font, without applying hinting to fit the curves + to the pixel grid. + + + Fonts may provide pre-rendered images for glyphs instead of or in addition to + outlines. This is most common for fonts that contain colored glyphs, such as + Emoji. To access these images, use hb_ot_color_reference_png() + or hb_ot_color_reference_svg(). + + + Another way in which fonts provide colored glyphs is via paint graphs that + combine glyph outlines with gradients and allow for transformations and + compositing. In its simplest form, this can be presented as a series of + layers that are rendered on top of each other, each with its own color. + HarfBuzz has the hb_ot_color_glyph_get_layers() to + access glyph data in this form. + + + In the general case, you have to use hb_font_paint_glyph() + and pass a hb_paint_funcs_t struct with callbacks to obtain paint + graphs for glyphs that have them. The hb_font_paint_glyph() + API can handle outline and image glyphs as well, so it provides a unified API for + access to glyph rendering information. +
diff --git a/libs/harfbuzz/docs/usermanual-getting-started.xml b/libs/harfbuzz/docs/usermanual-getting-started.xml index eb8c1d728..7048b4e86 100644 --- a/libs/harfbuzz/docs/usermanual-getting-started.xml +++ b/libs/harfbuzz/docs/usermanual-getting-started.xml @@ -229,9 +229,13 @@ + // If you know the direction, script, and language hb_buffer_set_direction(buf, HB_DIRECTION_LTR); hb_buffer_set_script(buf, HB_SCRIPT_LATIN); hb_buffer_set_language(buf, hb_language_from_string("en", -1)); + + // If you don't know the direction, script, and language + hb_buffer_guess_segment_properties(buffer); diff --git a/libs/harfbuzz/docs/usermanual-integration.xml b/libs/harfbuzz/docs/usermanual-integration.xml index 5d31ec268..8d8fde0e5 100644 --- a/libs/harfbuzz/docs/usermanual-integration.xml +++ b/libs/harfbuzz/docs/usermanual-integration.xml @@ -174,7 +174,9 @@ HarfBuzz provides integration points with FreeType at the face-object and font-object level and for the font-functions - virtual-method structure of a font object. To use the + virtual-method structure of a font object. These functions + make it easy for clients that use FreeType for rasterization + or font-loading, to use HarfBuzz for shaping. To use the FreeType-integration API, include the hb-ft.h header. @@ -245,7 +247,7 @@ HarfBuzz also provides a utility function called - hb_ft_font_has_changed() that you should + hb_ft_font_changed() that you should call whenever you have altered the properties of your underlying FT_Face, as well as a hb_ft_get_face() that you can call on an @@ -308,7 +310,49 @@ it when it is unneeded.
- + +
+ Cairo integration + + + Cairo is a 2D graphics library that is frequently used together + with GTK and Pango. Cairo supports rendering text using FreeType, or + by using callback-based 'user fonts'. + + + HarfBuzz provides integration points with cairo for fonts as well as + for buffers. To use the Cairo-integration API, link against libharfbuzz-cairo, + and include the hb-cairo.h header. For easy buildsystem + integration, HarfBuzz comes with a harfbuzz-cairo.pc + pkg-config file. + + + To create a cairo_scaled_font_t font from a HarfBuzz + hb_font_t, you can use hb_cairo_font_face_create_for_font() + or hb_cairo_font_face_create_for_face(). The former API + applies variations and synthetic slant from the hb_font_t when + rendering, the latter takes them from the cairo_font_options_t + that were passed when creating the cairo_scaled_font_t. + + + The Cairo fonts created in this way make use of Cairo's user-font facilities. + They can be used to render on any Cairo context, and provide full support for + font rendering features, including color. One current limitation of the + implementation is that it does not support hinting for glyph outlines. + + + When using color fonts with this API, the color palette index is taken from + the cairo_font_options_t (with new enough Cairo), and the foreground + color is extracted from the source of the Cairo context. + + + To render the results of shaping a piece of text, use + hb_cairo_glyphs_from_buffer() to obtain the glyphs in + a form that can be passed to cairo_show_text_glyphs() or + cairo_show_glyphs(). + +
+
Uniscribe integration diff --git a/libs/harfbuzz/docs/wasm-shaper.md b/libs/harfbuzz/docs/wasm-shaper.md new file mode 100644 index 000000000..34829b53b --- /dev/null +++ b/libs/harfbuzz/docs/wasm-shaper.md @@ -0,0 +1,544 @@ +# The web assembly shaper + +If the standard OpenType shaping engine doesn't give you enough flexibility, Harfbuzz allows you to write your own shaping engine in WebAssembly and embed it into your font! Any font which contains a `Wasm` table will be passed to the WebAssembly shaper. + +## What you can and can't do: the WASM shaper's role in shaping + +The Harfbuzz shaping engine, unlike its counterparts CoreText and DirectWrite, is only responsible for a small part of the text rendering process. Specifically, Harfbuzz is purely responsible for *shaping*; although Harfbuzz does have APIs for accessing glyph outlines, typically other libraries in the free software text rendering stack are responsible for text segmentation into runs, outline scaling and rasterizing, setting text on lines, and so on. + +Harfbuzz is therefore restricted to turning a buffer of codepoints for a segmented run of the same script, language, font, and variation settings, into glyphs and positioning them. This is also all that you can do with the WASM shaper; you can influence the process of mapping a string of characters into an array of glyphs, you can determine how those glyphs are positioned and their advance widths, but you cannot manipulate outlines, variations, line breaks, or affect text layout between texts of different font, variation, language, script or OpenType feature selection. + +## The WASM shaper interface + +The WASM code inside a font is expected to export a function called `shape` which takes five int32 arguments and returns an int32 status value. (Zero for failure, any other value for success.) Three of the five arguments are tokens which can be passed to the API functions exported to your WASM code by the host shaping engine: + +* A *shape plan* token, which can largely be ignored. +* A *font* token. +* A *buffer* token. +* A *feature* array. +* The number of features. + +The general goal of WASM shaping involves receiving and manipulating a *buffer contents* structure, which is an array of *infos* and *positions* (as defined below). Initially this buffer will represent an input string in Unicode codepoints. By the end of your `shape` function, it should represent a set of glyph IDs and their positions. (User-supplied WASM code will manipulate the buffer through *buffer tokens*; the `buffer_copy_contents` and `buffer_set_contents` API functions, defined below, use these tokens to exchange buffer information with the host shaping engine.) + +* The `buffer_contents_t` structure + +| type | field | description| +| - | - | - | +| uint32 | length | Number of items (characters or glyphs) in the buffer +| glyph_info_t | infos | An array of `length` glyph infos | +| glyph_position_t | positions | An array of `length` glyph positions | + +* The `glyph_info_t` structure + +| type | field | description| +| - | - | - | +| uint32 | codepoint | (On input) A Unicode codepoint. (On output) A glyph ID. | +| uint32 | mask | Unused in WASM; can be user-defined | +| uint32 | cluster | Index of start of this graphical cluster in input string | +| uint32 | var1 | Reserved | +| uint32 | var2 | Reserved | + +The `cluster` field is used to glyphs in the output glyph stream back to characters in the input Unicode sequence for hit testing, cursor positioning, etc. It must be set to a monotonically increasing value across the buffer. + +* The `glyph_position_t` structure + +| type | field | description| +| - | - | - | +| int32 | x_advance | X advance of the glyph | +| int32 | y_advance | Y advance of the glyph | +| int32 | x_offset | X offset of the glyph | +| int32 | y_offset | Y offset of the glyph | +| uint32 | var | Reserved | + +* The `feature_t` array + +To communicate user-selected OpenType features to the user-defined WASM shaper, the host shaping engine passes an array of feature structures: + +| type | field | description| +| - | - | - | +| uint32 | tag | Byte-encoded feature tag | +| uint32 | value | Value: 0=off, 1=on, other values used for alternate selection | +| uint32 | start | Index into the input string representing start of the active region for this feature selection (0=start of string) | +| uint32 | end | Index into the input string representing end of the active region for this feature selection (-1=end of string) | + +## API functions available + +To assist the shaping code in mapping codepoints to glyphs, the WASM shaper exports the following functions. Note that these are the low level API functions; WASM authors may prefer to use higher-level abstractions around these functions, such as the `harfbuzz-wasm` Rust crate provided by Harfbuzz. + +### Sub-shaping + +* `shape_with` + +```C +bool shape_with( + uint32 font_token, + uint32 buffer_token, + feature_t* features, + uint32 num_features, + char* shaper +) +``` + +Run another shaping engine's shaping process on the given font and buffer. The only shaping engine guaranteed to be available is `ot`, the OpenType shaper, but others may also be available. This allows the WASM author to process a buffer "normally", before further manipulating it. + +### Buffer access + +* `buffer_copy_contents` + +```C +bool buffer_copy_contents( + uint32 buffer_token, + buffer_contents_t* buffer_contents +) +``` + +Retrieves the contents of the host shaping engine's buffer into the `buffer_contents` structure. This should typically be called at the beginning of shaping. + +* `buffer_set_contents` + +```C +bool buffer_set_contents( + uint32 buffer_token, + buffer_contents_t* buffer_contents +) +``` + +Copy the `buffer_contents` structure back into the host shaping engine's buffer. This should typically be called at the end of shaping. + +* `buffer_contents_free` + +```C +bool buffer_contents_free(buffer_contents_t* buffer_contents) +``` + +Releases the memory taken up by the buffer contents structure. + +* `buffer_contents_realloc` + +```C +bool buffer_contents_realloc( + buffer_contents_t* buffer_contents, + uint32 size +) +``` + +Requests that the buffer contents structure be resized to the given size. + +* `buffer_get_direction` + +```C +uint32 buffer_get_direction(uint32 buffer_token) +``` + +Returns the buffer's direction: + +* 0 = invalid +* 4 = left to right +* 5 = right to left +* 6 = top to bottom +* 7 = bottom to top + +* `buffer_get_script` + +```C +uint32 buffer_get_script(uint32 buffer_token) +``` + +Returns the byte-encoded OpenType script tag of the buffer. + +* `buffer_reverse` + +```C +void buffer_reverse(uint32 buffer_token) +``` + +Reverses the order of items in the buffer. + +* `buffer_reverse_clusters` + +```C +void buffer_reverse_clusters(uint32 buffer_token) +``` + +Reverses the order of items in the buffer while keeping items of the same cluster together. + +## Font handling functions + +(In the following functions, a *font* is a specific instantiation of a *face* at a particular scale factor and variation position.) + +* `font_create` + +```C +uint32 font_create(uint32 face_token) +``` + +Returns a new *font token* from the given *face token*. + +* `font_get_face` + +```C +uint32 font_get_face(uint32 font_token) +``` + +Creates a new *face token* from the given *font token*. + +* `font_get_scale` + +```C +void font_get_scale( + uint32 font_token, + int32* x_scale, + int32* y_scale +) +``` + +Returns the scale of the current font. + +* `font_get_glyph` + +```C +uint32 font_get_glyph( + uint32 font_token, + uint32 codepoint, + uint32 variation_selector +) +``` + +Returns the nominal glyph ID for the given codepoint, using the `cmap` table of the font to map Unicode codepoint (and variation selector) to glyph ID. + +* `font_get_glyph_h_advance`/`font_get_glyph_v_advance` + +```C +uint32 font_get_glyph_h_advance(uint32 font_token, uint32 glyph_id) +uint32 font_get_glyph_v_advance(uint32 font_token, uint32 glyph_id) +``` + +Returns the default horizontal and vertical advance respectively for the given glyph ID the current scale and variations settings. + +* `font_get_glyph_extents` + +```C +typedef struct +{ + uint32 x_bearing; + uint32 y_bearing; + uint32 width; + uint32 height; +} glyph_extents_t; + +bool font_get_glyph_extents( + uint32 font_token, + uint32 glyph_id, + glyph_extents_t* extents +) +``` + +Returns the glyph's extents for the given glyph ID at current scale and variation settings. + +* `font_glyph_to_string` + +```C +void font_glyph_to_string( + uint32 font_token, + uint32 glyph_id, + char* string, + uint32 size +) +``` + +Copies the name of the given glyph, or, if no name is available, a string of the form `gXXXX` into the given string. + +* `font_copy_glyph_outline` + +```C +typedef struct +{ + float x; + float y; + uint32_t type; +} glyph_outline_point_t; + +typedef struct +{ + uint32_t n_points; + glyph_outline_point_t* points; + uint32_t n_contours; + uint32_t* contours; +} glyph_outline_t; + +bool font_copy_glyph_outline( + uint32 font_token, + uint32 glyph_id, + glyph_outline_t* outline +); +``` + +Copies the outline of the given glyph ID, at current scale and variation settings, into the outline structure provided. The outline structure returns an array of points (specifying coordinates and whether the point is oncurve or offcurve) and an array of indexes into the points array representing the end of each contour, similar to the `glyf` table structure. + +* `font_copy_coords`/`font_set_coords` + +```C +typedef struct +{ + uint32 length; + int32* coords; +} coords_t; + +bool font_copy_coords(uint32 font_token, &coords_t coords); +bool font_set_coords(uint32 font_token, &coords_t coords); +``` + +`font_copy_coords` copies the font's variation coordinates into the given structure; the resulting structure has `length` equal to the number of variation axes, with each member of the `coords` array being a F2DOT14 encoding of the normalized variation value. + +`font_set_coords` sets the font's variation coordinates. Because the WASM shaper is only responsible for shaping and positioning, not outline drawing, the user should *not* expect this to affect the rendered outlines; the function is only useful in very limited circumstances, such as when instantiating a second variable font and sub-shaping a buffer using this new font. + +## Face handling functions + +* `face_create` + +```C +typedef struct +{ + uint32_t length; + char* data; +} blob_t; + +uint32 font_get_face(blob_t* blob) +``` + +Creates a new *face token* from the given binary data. + +* `face_copy_table` + +```C +void face_copy_table(uint32 face_token, uint32 tag, blob_t* blob) +``` + +Copies the binary data in the OpenType table referenced by `tag` into the supplied `blob` structure. + +* `face_get_upem` + +```C +uint32 font_get_upem(uint32 face_token) +``` + +Returns the units-per-em of the font face. + +### Other functions + +* `blob_free` + +```C +void blob_free(blob_t* blob) +``` + +Frees the memory allocated to a blob structure. + +* `glyph_outline_free` + +```C +void glyph_outline_free(glyph_outline_t* glyph_outline) +``` + +Frees the memory allocated to a glyph outline structure. + +* `script_get_horizontal_direction` + +```C +uint32 script_get_horizontal_direction(uint32 tag) +``` + +Returns the horizontal direction for the given ISO 15924 script tag. For return values, see `buffer_get_direction` above. + +* `debugprint` / `debugprint1` ... `debugprint4` + +```C +void debugprint(char* str) +void debugprint1(char* str, int32 arg1) +void debugprint2(char* str, int32 arg1, int32 arg2) +void debugprint3(char* str, int32 arg1, int32 arg2, int32 arg3) +void debugprint4( + char* str, + int32 arg1, + int32 arg2, + int32 arg3, + int32 arg4 +) +``` + +Produces a debugging message in the host shaper's log output; the variants `debugprint1` ... `debugprint4` suffix the message with a comma-separated list of the integer arguments. + +## Enabling the WASM shaper when building Harfbuzz + +First, you will need the `wasm-micro-runtime` library installed on your computer. Download `wasm-micro-runtime` from [its GitHub repository](https://github.com/bytecodealliance/wasm-micro-runtime/tree/main); then follow [the instructions for building](https://github.com/bytecodealliance/wasm-micro-runtime/blob/main/product-mini/README.md), except run the cmake command from the repository root directory and add the `-DWAMR_BUILD_REF_TYPES=1` flag to the `cmake` line. (You may want to enable "fast JIT".) Then, install it. + +So, for example: + +``` +$ cmake -B build -DWAMR_BUILD_REF_TYPES=1 -DWAMR_BUILD_FAST_JIT=1 +$ cmake --build build --parallel +$ sudo cmake --build build --target install +``` + +(If you don't want to install `wasm-micro-runtime` globally, you can copy `libiwasm.*` and `libvmlib.a` into a directory that your compiler can see when building Harfbuzz.) + +Once `wasm-micro-runtime` is installed, to enable the WASM shaper, you need to add the string `-Dwasm=enabled` to your meson build line. For example: + +``` +$ meson setup build -Dwasm=enabled +... + Additional shapers + Graphite2 : NO + WebAssembly (experimental): YES +... +$ meson compile -C build +``` + +## How to write a shaping engine in Rust + +You may write shaping engines in any language supported by WASM, by conforming to the API described above, but Rust is particularly easy, and we have one of those high-level interface wrappers which makes the process easier. Here are the steps to create an example shaping engine in Rust: (These examples can also be found in [their own reposotry](https://github.com/harfbuzz/harfbuzz-wasm-examples)) + +* First, install wasm-pack, which helps us to generate optimized WASM files. It writes some Javascript bridge code that we don't need, but it makes the build and deployment process much easier: + +``` +$ cargo install wasm-pack +``` + +* Now let's create a new library: + +``` +$ cargo new --lib hello-wasm +``` + +* We need the target to be a dynamic library, and we're going to use `bindgen` to export our Rust function to WASM, so let's put these lines in the `Cargo.toml`. The Harfbuzz sources contain a Rust crate which makes it easy to create the shaper, so we'll specify that as a dependency as well: + +```toml +[lib] +crate-type = ["cdylib"] +[dependencies] +wasm-bindgen = "0.2" +harfbuzz-wasm = { path = "your-harfbuzz-source/src/wasm/rust/harfbuzz-wasm"} +``` + +* +* And now we'll create our shaper code. In `src/lib.rs`: + +```rust +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub fn shape(_shape_plan:u32, font_ref: u32, buf_ref: u32, _features: u32, _num_features: u32) -> i32 { + 1 // success! +} +``` + +This exports a shaping function which takes four arguments, tokens representing the shaping plan, the font and the buffer, and returns a status value. We can pass these tokens back to Harfbuzz in order to use its native functions on the font and buffer objects. More on native functions later - let's get this shaper compiled and added into a font: + +* To compile the shaper, run `wasm-pack build --target nodejs`: + +``` +INFO]: 🎯 Checking for the Wasm target... +[INFO]: 🌀 Compiling to Wasm... + Compiling hello-wasm v0.1.0 (...) + Finished release [optimized] target(s) in 0.20s +[WARN]: ⚠️ origin crate has no README +[INFO]: ⬇️ Installing wasm-bindgen... +[INFO]: Optimizing wasm binaries with `wasm-opt`... +[INFO]: Optional fields missing from Cargo.toml: 'description', 'repository', and 'license'. These are not necessary, but recommended +[INFO]: ✨ Done in 0.40s +``` + +You'll find the output WASM file in `pkg/hello_wasm_bg.wasm` + +* Now we need to get it into a font. + +We provide a utility to do this called `addTable.py` in the `src/` directory: + +``` +% python3 ~/harfbuzz/src/addTable.py test.ttf test-wasm.ttf pkg/hello_wasm_bg.wasm +``` + +And now we can run it! + +``` +% hb-shape test-wasm.ttf abc --shapers=wasm +[cent=0|sterling=1|fraction=2] +``` + +(The `--shapers=wasm` isn't necessary, as any font with a `Wasm` table will be sent to the WASM shaper if it's enabled, but it proves the point.) + +Congratulations! Our shaper did nothing, but in Rust! Now let's do something - it's time for the Hello World of WASM shaping. + +* To say hello world, we're going to have to use a native function. + +In debugging builds of Harfbuzz, we can print some output from the web assembly module to the host's standard output using the `debug` function. To make this easier, we've got the `harfbuzz-wasm` crate: + +```rust +use harfbuzz_wasm::debug; + +#[wasm_bindgen] +pub fn shape(_shape_plan:u32, _font_ref: u32, _buf_ref: u32, _features: u32, _num_features: u32) -> i32 { + debug("Hello from Rust!\n"); + 1 +} +``` + +With this compiled into a WASM module, and installed into our font again, finally our fonts can talk to us! + +``` +$ hb-shape test-wasm.ttf abc +Hello from Rust! +[cent=0|sterling=1|fraction=2] +``` + +Now let's start to do some actual, you know, *shaping*. The first thing a shaping engine normally does is (a) map the items in the buffer from Unicode codepoints into glyphs in the font, and (b) set the advance width of the buffer items to the default advance width for those glyphs. We're going to need to interrogate the font for this information, and write back to the buffer. Harfbuzz provides us with opaque pointers to the memory for the font and buffer, but we can turn those into useful Rust structures using the `harfbuzz-wasm` crate again: + +```rust +use wasm_bindgen::prelude::*; +use harfbuzz_wasm::{Font, GlyphBuffer}; + +#[wasm_bindgen] +pub fn shape(_shape_plan:u32, font_ref: u32, buf_ref: u32, _features: u32, _num_features: u32) -> i32 { + let font = Font::from_ref(font_ref); + let mut buffer = GlyphBuffer::from_ref(buf_ref); + for mut item in buffer.glyphs.iter_mut() { + // Map character to glyph + item.codepoint = font.get_glyph(item.codepoint, 0); + // Set advance width + item.x_advance = font.get_glyph_h_advance(item.codepoint); + } + 1 +} +``` + +The `GlyphBuffer`, unlike in Harfbuzz, combines positioning and information in a single structure, to save you having to zip and unzip all the time. It also takes care of marshalling the buffer back to Harfbuzz-land; when a GlyphBuffer is dropped, it writes its contents back through the reference into Harfbuzz's address space. (If you want a different representation of buffer items, you can have one: `GlyphBuffer` is implemented as a `Buffer`, and if you make your own struct which implements the `BufferItem` trait, you can make a buffer out of that instead.) + +One easy way to write your own shapers is to make use of OpenType shaping for the majority of your shaping work, and then make changes to the pre-shaped buffer afterwards. You can do this using the `Font.shape_with` method. Run this on a buffer reference, and then construct your `GlyphBuffer` object afterwards: + +```rust +use harfbuzz_wasm::{Font, GlyphBuffer}; +use tiny_rng::{Rand, Rng}; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub fn shape(_shape_plan:u32, font_ref: u32, buf_ref: u32, _features: u32, _num_features: u32) -> i32 { + let mut rng = Rng::from_seed(123456); + + // Use the default OpenType shaper + let font = Font::from_ref(font_ref); + font.shape_with(buf_ref, "ot"); + + // Now we have a buffer with glyph ids, advance widths etc. + // already filled in. + let mut buffer = GlyphBuffer::from_ref(buf_ref); + for mut item in buffer.glyphs.iter_mut() { + // Randomize it! + item.x_offset = ((rng.rand_u32() as i32) >> 24) - 120; + item.y_offset = ((rng.rand_u32() as i32) >> 24) - 120; + } + + 1 +} +``` + +See the documentation for the `harfbuzz-wasm` crate for all the other diff --git a/libs/harfbuzz/git.mk b/libs/harfbuzz/git.mk deleted file mode 100644 index cd52db1eb..000000000 --- a/libs/harfbuzz/git.mk +++ /dev/null @@ -1,401 +0,0 @@ -# git.mk, a small Makefile to autogenerate .gitignore files -# for autotools-based projects. -# -# Copyright 2009, Red Hat, Inc. -# Copyright 2010,2011,2012,2013 Behdad Esfahbod -# Written by Behdad Esfahbod -# -# Copying and distribution of this file, with or without modification, -# is permitted in any medium without royalty provided the copyright -# notice and this notice are preserved. -# -# The latest version of this file can be downloaded from: -GIT_MK_URL = https://raw.githubusercontent.com/behdad/git.mk/master/git.mk -# -# Bugs, etc, should be reported upstream at: -# https://github.com/behdad/git.mk -# -# To use in your project, import this file in your git repo's toplevel, -# then do "make -f git.mk". This modifies all Makefile.am files in -# your project to -include git.mk. Remember to add that line to new -# Makefile.am files you create in your project, or just rerun the -# "make -f git.mk". -# -# This enables automatic .gitignore generation. If you need to ignore -# more files, add them to the GITIGNOREFILES variable in your Makefile.am. -# But think twice before doing that. If a file has to be in .gitignore, -# chances are very high that it's a generated file and should be in one -# of MOSTLYCLEANFILES, CLEANFILES, DISTCLEANFILES, or MAINTAINERCLEANFILES. -# -# The only case that you need to manually add a file to GITIGNOREFILES is -# when remove files in one of mostlyclean-local, clean-local, distclean-local, -# or maintainer-clean-local make targets. -# -# Note that for files like editor backup, etc, there are better places to -# ignore them. See "man gitignore". -# -# If "make maintainer-clean" removes the files but they are not recognized -# by this script (that is, if "git status" shows untracked files still), send -# me the output of "git status" as well as your Makefile.am and Makefile for -# the directories involved and I'll diagnose. -# -# For a list of toplevel files that should be in MAINTAINERCLEANFILES, see -# Makefile.am.sample in the git.mk git repo. -# -# Don't EXTRA_DIST this file. It is supposed to only live in git clones, -# not tarballs. It serves no useful purpose in tarballs and clutters the -# build dir. -# -# This file knows how to handle autoconf, automake, libtool, gtk-doc, -# gnome-doc-utils, yelp.m4, mallard, intltool, gsettings, dejagnu, appdata, -# appstream, hotdoc. -# -# This makefile provides the following targets: -# -# - all: "make all" will build all gitignore files. -# - gitignore: makes all gitignore files in the current dir and subdirs. -# - .gitignore: make gitignore file for the current dir. -# - gitignore-recurse: makes all gitignore files in the subdirs. -# -# KNOWN ISSUES: -# -# - Recursive configure doesn't work as $(top_srcdir)/git.mk inside the -# submodule doesn't find us. If you have configure.{in,ac} files in -# subdirs, add a proxy git.mk file in those dirs that simply does: -# "include $(top_srcdir)/../git.mk". Add more ..'s to your taste. -# And add those files to git. See vte/gnome-pty-helper/git.mk for -# example. -# - - - -############################################################################### -# Variables user modules may want to add to toplevel MAINTAINERCLEANFILES: -############################################################################### - -# -# Most autotools-using modules should be fine including this variable in their -# toplevel MAINTAINERCLEANFILES: -GITIGNORE_MAINTAINERCLEANFILES_TOPLEVEL = \ - $(srcdir)/aclocal.m4 \ - $(srcdir)/autoscan.log \ - $(srcdir)/configure.scan \ - `AUX_DIR=$(srcdir)/$$(cd $(top_srcdir); $(AUTOCONF) --trace 'AC_CONFIG_AUX_DIR:$$1' ./configure.ac); \ - test "x$$AUX_DIR" = "x$(srcdir)/" && AUX_DIR=$(srcdir); \ - for x in \ - ar-lib \ - compile \ - config.guess \ - config.rpath \ - config.sub \ - depcomp \ - install-sh \ - ltmain.sh \ - missing \ - mkinstalldirs \ - test-driver \ - ylwrap \ - ; do echo "$$AUX_DIR/$$x"; done` \ - `cd $(top_srcdir); $(AUTOCONF) --trace 'AC_CONFIG_HEADERS:$$1' ./configure.ac | \ - head -n 1 | while read f; do echo "$(srcdir)/$$f.in"; done` -# -# All modules should also be fine including the following variable, which -# removes automake-generated Makefile.in files: -GITIGNORE_MAINTAINERCLEANFILES_MAKEFILE_IN = \ - `cd $(top_srcdir); $(AUTOCONF) --trace 'AC_CONFIG_FILES:$$1' ./configure.ac | \ - while read f; do \ - case $$f in Makefile|*/Makefile) \ - test -f "$(srcdir)/$$f.am" && echo "$(srcdir)/$$f.in";; esac; \ - done` -# -# Modules that use libtool and use AC_CONFIG_MACRO_DIR() may also include this, -# though it's harmless to include regardless. -GITIGNORE_MAINTAINERCLEANFILES_M4_LIBTOOL = \ - `MACRO_DIR=$(srcdir)/$$(cd $(top_srcdir); $(AUTOCONF) --trace 'AC_CONFIG_MACRO_DIR:$$1' ./configure.ac); \ - if test "x$$MACRO_DIR" != "x$(srcdir)/"; then \ - for x in \ - libtool.m4 \ - ltoptions.m4 \ - ltsugar.m4 \ - ltversion.m4 \ - lt~obsolete.m4 \ - ; do echo "$$MACRO_DIR/$$x"; done; \ - fi` -# -# Modules that use gettext and use AC_CONFIG_MACRO_DIR() may also include this, -# though it's harmless to include regardless. -GITIGNORE_MAINTAINERCLEANFILES_M4_GETTEXT = \ - `MACRO_DIR=$(srcdir)/$$(cd $(top_srcdir); $(AUTOCONF) --trace 'AC_CONFIG_MACRO_DIR:$$1' ./configure.ac); \ - if test "x$$MACRO_DIR" != "x$(srcdir)/"; then \ - for x in \ - codeset.m4 \ - extern-inline.m4 \ - fcntl-o.m4 \ - gettext.m4 \ - glibc2.m4 \ - glibc21.m4 \ - iconv.m4 \ - intdiv0.m4 \ - intl.m4 \ - intldir.m4 \ - intlmacosx.m4 \ - intmax.m4 \ - inttypes-pri.m4 \ - inttypes_h.m4 \ - lcmessage.m4 \ - lib-ld.m4 \ - lib-link.m4 \ - lib-prefix.m4 \ - lock.m4 \ - longlong.m4 \ - nls.m4 \ - po.m4 \ - printf-posix.m4 \ - progtest.m4 \ - size_max.m4 \ - stdint_h.m4 \ - threadlib.m4 \ - uintmax_t.m4 \ - visibility.m4 \ - wchar_t.m4 \ - wint_t.m4 \ - xsize.m4 \ - ; do echo "$$MACRO_DIR/$$x"; done; \ - fi` - - - -############################################################################### -# Default rule is to install ourselves in all Makefile.am files: -############################################################################### - -git-all: git-mk-install - -git-mk-install: - @echo "Installing git makefile" - @any_failed=; \ - find "`test -z "$(top_srcdir)" && echo . || echo "$(top_srcdir)"`" -name Makefile.am | while read x; do \ - if grep 'include .*/git.mk' $$x >/dev/null; then \ - echo "$$x already includes git.mk"; \ - else \ - failed=; \ - echo "Updating $$x"; \ - { cat $$x; \ - echo ''; \ - echo '-include $$(top_srcdir)/git.mk'; \ - } > $$x.tmp || failed=1; \ - if test x$$failed = x; then \ - mv $$x.tmp $$x || failed=1; \ - fi; \ - if test x$$failed = x; then : else \ - echo "Failed updating $$x"; >&2 \ - any_failed=1; \ - fi; \ - fi; done; test -z "$$any_failed" - -git-mk-update: - wget $(GIT_MK_URL) -O $(top_srcdir)/git.mk - -.PHONY: git-all git-mk-install git-mk-update - - - -############################################################################### -# Actual .gitignore generation: -############################################################################### - -$(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk $(top_srcdir)/configure.ac - @echo "git.mk: Generating $@" - @{ \ - if test "x$(DOC_MODULE)" = x -o "x$(DOC_MAIN_SGML_FILE)" = x; then :; else \ - for x in \ - $(DOC_MODULE)-decl-list.txt \ - $(DOC_MODULE)-decl.txt \ - tmpl/$(DOC_MODULE)-unused.sgml \ - "tmpl/*.bak" \ - $(REPORT_FILES) \ - $(DOC_MODULE).pdf \ - xml html \ - ; do echo "/$$x"; done; \ - FLAVOR=$$(cd $(top_srcdir); $(AUTOCONF) --trace 'GTK_DOC_CHECK:$$2' ./configure.ac); \ - case $$FLAVOR in *no-tmpl*) echo /tmpl;; esac; \ - if echo "$(SCAN_OPTIONS)" | grep -q "\-\-rebuild-types"; then \ - echo "/$(DOC_MODULE).types"; \ - fi; \ - if echo "$(SCAN_OPTIONS)" | grep -q "\-\-rebuild-sections"; then \ - echo "/$(DOC_MODULE)-sections.txt"; \ - fi; \ - if test "$(abs_srcdir)" != "$(abs_builddir)" ; then \ - for x in \ - $(SETUP_FILES) \ - $(DOC_MODULE).types \ - ; do echo "/$$x"; done; \ - fi; \ - fi; \ - if test "x$(DOC_MODULE)$(DOC_ID)" = x -o "x$(DOC_LINGUAS)" = x; then :; else \ - for lc in $(DOC_LINGUAS); do \ - for x in \ - $(if $(DOC_MODULE),$(DOC_MODULE).xml) \ - $(DOC_PAGES) \ - $(DOC_INCLUDES) \ - ; do echo "/$$lc/$$x"; done; \ - done; \ - for x in \ - $(_DOC_OMF_ALL) \ - $(_DOC_DSK_ALL) \ - $(_DOC_HTML_ALL) \ - $(_DOC_MOFILES) \ - $(DOC_H_FILE) \ - "*/.xml2po.mo" \ - "*/*.omf.out" \ - ; do echo /$$x; done; \ - fi; \ - if test "x$(HOTDOC)" = x; then :; else \ - $(foreach project, $(HOTDOC_PROJECTS),echo "/$(call HOTDOC_TARGET,$(project))"; \ - echo "/$(shell $(call HOTDOC_PROJECT_COMMAND,$(project)) --get-conf-path output)" ; \ - echo "/$(shell $(call HOTDOC_PROJECT_COMMAND,$(project)) --get-private-folder)" ; \ - ) \ - for x in \ - .hotdoc.d \ - ; do echo "/$$x"; done; \ - fi; \ - if test "x$(HELP_ID)" = x -o "x$(HELP_LINGUAS)" = x; then :; else \ - for lc in $(HELP_LINGUAS); do \ - for x in \ - $(HELP_FILES) \ - "$$lc.stamp" \ - "$$lc.mo" \ - ; do echo "/$$lc/$$x"; done; \ - done; \ - fi; \ - if test "x$(gsettings_SCHEMAS)" = x; then :; else \ - for x in \ - $(gsettings_SCHEMAS:.xml=.valid) \ - $(gsettings__enum_file) \ - ; do echo "/$$x"; done; \ - fi; \ - if test "x$(appdata_XML)" = x; then :; else \ - for x in \ - $(appdata_XML:.xml=.valid) \ - ; do echo "/$$x"; done; \ - fi; \ - if test "x$(appstream_XML)" = x; then :; else \ - for x in \ - $(appstream_XML:.xml=.valid) \ - ; do echo "/$$x"; done; \ - fi; \ - if test -f $(srcdir)/po/Makefile.in.in; then \ - for x in \ - ABOUT-NLS \ - po/Makefile.in.in \ - po/Makefile.in.in~ \ - po/Makefile.in \ - po/Makefile \ - po/Makevars.template \ - po/POTFILES \ - po/Rules-quot \ - po/stamp-it \ - po/stamp-po \ - po/.intltool-merge-cache \ - "po/*.gmo" \ - "po/*.header" \ - "po/*.mo" \ - "po/*.sed" \ - "po/*.sin" \ - po/$(GETTEXT_PACKAGE).pot \ - intltool-extract.in \ - intltool-merge.in \ - intltool-update.in \ - ; do echo "/$$x"; done; \ - fi; \ - if test -f $(srcdir)/configure; then \ - for x in \ - autom4te.cache \ - configure \ - config.h \ - stamp-h1 \ - libtool \ - config.lt \ - ; do echo "/$$x"; done; \ - fi; \ - if test "x$(DEJATOOL)" = x; then :; else \ - for x in \ - $(DEJATOOL) \ - ; do echo "/$$x.sum"; echo "/$$x.log"; done; \ - echo /site.exp; \ - fi; \ - if test "x$(am__dirstamp)" = x; then :; else \ - echo "$(am__dirstamp)"; \ - fi; \ - if test "x$(findstring libtool,$(LTCOMPILE))" = x -a "x$(findstring libtool,$(LTCXXCOMPILE))" = x -a "x$(GTKDOC_RUN)" = x; then :; else \ - for x in \ - "*.lo" \ - ".libs" "_libs" \ - ; do echo "$$x"; done; \ - fi; \ - for x in \ - .gitignore \ - $(GITIGNOREFILES) \ - $(CLEANFILES) \ - $(PROGRAMS) $(check_PROGRAMS) $(EXTRA_PROGRAMS) \ - $(LIBRARIES) $(check_LIBRARIES) $(EXTRA_LIBRARIES) \ - $(LTLIBRARIES) $(check_LTLIBRARIES) $(EXTRA_LTLIBRARIES) \ - so_locations \ - $(MOSTLYCLEANFILES) \ - $(TEST_LOGS) \ - $(TEST_LOGS:.log=.trs) \ - $(TEST_SUITE_LOG) \ - $(TESTS:=.test) \ - "*.gcda" \ - "*.gcno" \ - $(DISTCLEANFILES) \ - $(am__CONFIG_DISTCLEAN_FILES) \ - $(CONFIG_CLEAN_FILES) \ - TAGS ID GTAGS GRTAGS GSYMS GPATH tags \ - "*.tab.c" \ - $(MAINTAINERCLEANFILES) \ - $(BUILT_SOURCES) \ - $(patsubst %.vala,%.c,$(filter %.vala,$(SOURCES))) \ - $(filter %_vala.stamp,$(DIST_COMMON)) \ - $(filter %.vapi,$(DIST_COMMON)) \ - $(filter $(addprefix %,$(notdir $(patsubst %.vapi,%.h,$(filter %.vapi,$(DIST_COMMON))))),$(DIST_COMMON)) \ - Makefile \ - Makefile.in \ - "*.orig" \ - "*.rej" \ - "*.bak" \ - "*~" \ - ".*.sw[nop]" \ - ".dirstamp" \ - ; do echo "/$$x"; done; \ - for x in \ - "*.$(OBJEXT)" \ - $(DEPDIR) \ - ; do echo "$$x"; done; \ - } | \ - sed "s@^/`echo "$(srcdir)" | sed 's/\(.\)/[\1]/g'`/@/@" | \ - sed 's@/[.]/@/@g' | \ - LC_ALL=C sort | uniq > .gitignore.tmp && \ - (mv .gitignore.tmp $@ || (echo "WARNING: Cannot create $@ file; skipping"; \ - $(RM) .gitignore.tmp)); - -all: $(srcdir)/.gitignore gitignore-recurse-maybe -gitignore: $(srcdir)/.gitignore gitignore-recurse - -gitignore-recurse-maybe: - @for subdir in $(DIST_SUBDIRS); do \ - case " $(SUBDIRS) " in \ - *" $$subdir "*) :;; \ - *) test "$$subdir" = . -o -e "$$subdir/.git" || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) gitignore || echo "Skipping $$subdir");; \ - esac; \ - done -gitignore-recurse: - @for subdir in $(DIST_SUBDIRS); do \ - test "$$subdir" = . -o -e "$$subdir/.git" || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) gitignore || echo "Skipping $$subdir"); \ - done - -maintainer-clean: gitignore-clean -gitignore-clean: - -rm -f $(srcdir)/.gitignore - -.PHONY: gitignore-clean gitignore gitignore-recurse gitignore-recurse-maybe diff --git a/libs/harfbuzz/m4/ax_check_link_flag.m4 b/libs/harfbuzz/m4/ax_check_link_flag.m4 deleted file mode 100644 index 819409a20..000000000 --- a/libs/harfbuzz/m4/ax_check_link_flag.m4 +++ /dev/null @@ -1,74 +0,0 @@ -# =========================================================================== -# https://www.gnu.org/software/autoconf-archive/ax_check_link_flag.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) -# -# DESCRIPTION -# -# Check whether the given FLAG works with the linker or gives an error. -# (Warnings, however, are ignored) -# -# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on -# success/failure. -# -# If EXTRA-FLAGS is defined, it is added to the linker's default flags -# when the check is done. The check is thus made with the flags: "LDFLAGS -# EXTRA-FLAGS FLAG". This can for example be used to force the linker to -# issue an error when a bad flag is given. -# -# INPUT gives an alternative input source to AC_LINK_IFELSE. -# -# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this -# macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG. -# -# LICENSE -# -# Copyright (c) 2008 Guido U. Draheim -# Copyright (c) 2011 Maarten Bosmans -# -# This program is free software: you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation, either version 3 of the License, or (at your -# option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General -# Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program. If not, see . -# -# As a special exception, the respective Autoconf Macro's copyright owner -# gives unlimited permission to copy, distribute and modify the configure -# scripts that are the output of Autoconf when processing the Macro. You -# need not follow the terms of the GNU General Public License when using -# or distributing such scripts, even though portions of the text of the -# Macro appear in them. The GNU General Public License (GPL) does govern -# all other use of the material that constitutes the Autoconf Macro. -# -# This special exception to the GPL applies to versions of the Autoconf -# Macro released by the Autoconf Archive. When you make and distribute a -# modified version of the Autoconf Macro, you may extend this special -# exception to the GPL to apply to your modified version as well. - -#serial 5 - -AC_DEFUN([AX_CHECK_LINK_FLAG], -[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF -AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl -AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [ - ax_check_save_flags=$LDFLAGS - LDFLAGS="$LDFLAGS $4 $1" - AC_LINK_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], - [AS_VAR_SET(CACHEVAR,[yes])], - [AS_VAR_SET(CACHEVAR,[no])]) - LDFLAGS=$ax_check_save_flags]) -AS_VAR_IF(CACHEVAR,yes, - [m4_default([$2], :)], - [m4_default([$3], :)]) -AS_VAR_POPDEF([CACHEVAR])dnl -])dnl AX_CHECK_LINK_FLAGS diff --git a/libs/harfbuzz/m4/ax_code_coverage.m4 b/libs/harfbuzz/m4/ax_code_coverage.m4 deleted file mode 100644 index 6484f0332..000000000 --- a/libs/harfbuzz/m4/ax_code_coverage.m4 +++ /dev/null @@ -1,264 +0,0 @@ -# =========================================================================== -# https://www.gnu.org/software/autoconf-archive/ax_code_coverage.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_CODE_COVERAGE() -# -# DESCRIPTION -# -# Defines CODE_COVERAGE_CPPFLAGS, CODE_COVERAGE_CFLAGS, -# CODE_COVERAGE_CXXFLAGS and CODE_COVERAGE_LIBS which should be included -# in the CPPFLAGS, CFLAGS CXXFLAGS and LIBS/LIBADD variables of every -# build target (program or library) which should be built with code -# coverage support. Also defines CODE_COVERAGE_RULES which should be -# substituted in your Makefile; and $enable_code_coverage which can be -# used in subsequent configure output. CODE_COVERAGE_ENABLED is defined -# and substituted, and corresponds to the value of the -# --enable-code-coverage option, which defaults to being disabled. -# -# Test also for gcov program and create GCOV variable that could be -# substituted. -# -# Note that all optimization flags in CFLAGS must be disabled when code -# coverage is enabled. -# -# Usage example: -# -# configure.ac: -# -# AX_CODE_COVERAGE -# -# Makefile.am: -# -# @CODE_COVERAGE_RULES@ -# my_program_LIBS = ... $(CODE_COVERAGE_LIBS) ... -# my_program_CPPFLAGS = ... $(CODE_COVERAGE_CPPFLAGS) ... -# my_program_CFLAGS = ... $(CODE_COVERAGE_CFLAGS) ... -# my_program_CXXFLAGS = ... $(CODE_COVERAGE_CXXFLAGS) ... -# -# This results in a "check-code-coverage" rule being added to any -# Makefile.am which includes "@CODE_COVERAGE_RULES@" (assuming the module -# has been configured with --enable-code-coverage). Running `make -# check-code-coverage` in that directory will run the module's test suite -# (`make check`) and build a code coverage report detailing the code which -# was touched, then print the URI for the report. -# -# In earlier versions of this macro, CODE_COVERAGE_LDFLAGS was defined -# instead of CODE_COVERAGE_LIBS. They are both still defined, but use of -# CODE_COVERAGE_LIBS is preferred for clarity; CODE_COVERAGE_LDFLAGS is -# deprecated. They have the same value. -# -# This code was derived from Makefile.decl in GLib, originally licenced -# under LGPLv2.1+. -# -# LICENSE -# -# Copyright (c) 2012, 2016 Philip Withnall -# Copyright (c) 2012 Xan Lopez -# Copyright (c) 2012 Christian Persch -# Copyright (c) 2012 Paolo Borelli -# Copyright (c) 2012 Dan Winship -# Copyright (c) 2015 Bastien ROUCARIES -# -# This library is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or (at -# your option) any later version. -# -# This library is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -# General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with this program. If not, see . - -#serial 25 - -AC_DEFUN([AX_CODE_COVERAGE],[ - dnl Check for --enable-code-coverage - AC_REQUIRE([AC_PROG_SED]) - - # allow to override gcov location - AC_ARG_WITH([gcov], - [AS_HELP_STRING([--with-gcov[=GCOV]], [use given GCOV for coverage (GCOV=gcov).])], - [_AX_CODE_COVERAGE_GCOV_PROG_WITH=$with_gcov], - [_AX_CODE_COVERAGE_GCOV_PROG_WITH=gcov]) - - AC_MSG_CHECKING([whether to build with code coverage support]) - AC_ARG_ENABLE([code-coverage], - AS_HELP_STRING([--enable-code-coverage], - [Whether to enable code coverage support]),, - enable_code_coverage=no) - - AM_CONDITIONAL([CODE_COVERAGE_ENABLED], [test x$enable_code_coverage = xyes]) - AC_SUBST([CODE_COVERAGE_ENABLED], [$enable_code_coverage]) - AC_MSG_RESULT($enable_code_coverage) - - AS_IF([ test "$enable_code_coverage" = "yes" ], [ - # check for gcov - AC_CHECK_TOOL([GCOV], - [$_AX_CODE_COVERAGE_GCOV_PROG_WITH], - [:]) - AS_IF([test "X$GCOV" = "X:"], - [AC_MSG_ERROR([gcov is needed to do coverage])]) - AC_SUBST([GCOV]) - - dnl Check if gcc is being used - AS_IF([ test "$GCC" = "no" ], [ - AC_MSG_ERROR([not compiling with gcc, which is required for gcov code coverage]) - ]) - - AC_CHECK_PROG([LCOV], [lcov], [lcov]) - AC_CHECK_PROG([GENHTML], [genhtml], [genhtml]) - - AS_IF([ test -z "$LCOV" ], [ - AC_MSG_ERROR([To enable code coverage reporting you must have lcov installed]) - ]) - - AS_IF([ test -z "$GENHTML" ], [ - AC_MSG_ERROR([Could not find genhtml from the lcov package]) - ]) - - dnl Build the code coverage flags - dnl Define CODE_COVERAGE_LDFLAGS for backwards compatibility - CODE_COVERAGE_CPPFLAGS="-DNDEBUG" - CODE_COVERAGE_CFLAGS="-O0 -g -fprofile-arcs -ftest-coverage" - CODE_COVERAGE_CXXFLAGS="-O0 -g -fprofile-arcs -ftest-coverage" - CODE_COVERAGE_LIBS="-lgcov" - CODE_COVERAGE_LDFLAGS="$CODE_COVERAGE_LIBS" - - AC_SUBST([CODE_COVERAGE_CPPFLAGS]) - AC_SUBST([CODE_COVERAGE_CFLAGS]) - AC_SUBST([CODE_COVERAGE_CXXFLAGS]) - AC_SUBST([CODE_COVERAGE_LIBS]) - AC_SUBST([CODE_COVERAGE_LDFLAGS]) - - [CODE_COVERAGE_RULES_CHECK=' - -$(A''M_V_at)$(MAKE) $(AM_MAKEFLAGS) -k check - $(A''M_V_at)$(MAKE) $(AM_MAKEFLAGS) code-coverage-capture -'] - [CODE_COVERAGE_RULES_CAPTURE=' - $(code_coverage_v_lcov_cap)$(LCOV) $(code_coverage_quiet) $(addprefix --directory ,$(CODE_COVERAGE_DIRECTORY)) --capture --output-file "$(CODE_COVERAGE_OUTPUT_FILE).tmp" --test-name "$(call code_coverage_sanitize,$(PACKAGE_NAME)-$(PACKAGE_VERSION))" --no-checksum --compat-libtool $(CODE_COVERAGE_LCOV_SHOPTS) $(CODE_COVERAGE_LCOV_OPTIONS) - $(code_coverage_v_lcov_ign)$(LCOV) $(code_coverage_quiet) $(addprefix --directory ,$(CODE_COVERAGE_DIRECTORY)) --remove "$(CODE_COVERAGE_OUTPUT_FILE).tmp" "/tmp/*" $(CODE_COVERAGE_IGNORE_PATTERN) --output-file "$(CODE_COVERAGE_OUTPUT_FILE)" $(CODE_COVERAGE_LCOV_SHOPTS) $(CODE_COVERAGE_LCOV_RMOPTS) - -@rm -f $(CODE_COVERAGE_OUTPUT_FILE).tmp - $(code_coverage_v_genhtml)LANG=C $(GENHTML) $(code_coverage_quiet) $(addprefix --prefix ,$(CODE_COVERAGE_DIRECTORY)) --output-directory "$(CODE_COVERAGE_OUTPUT_DIRECTORY)" --title "$(PACKAGE_NAME)-$(PACKAGE_VERSION) Code Coverage" --legend --show-details "$(CODE_COVERAGE_OUTPUT_FILE)" $(CODE_COVERAGE_GENHTML_OPTIONS) - @echo "file://$(abs_builddir)/$(CODE_COVERAGE_OUTPUT_DIRECTORY)/index.html" -'] - [CODE_COVERAGE_RULES_CLEAN=' -clean: code-coverage-clean -distclean: code-coverage-clean -code-coverage-clean: - -$(LCOV) --directory $(top_builddir) -z - -rm -rf $(CODE_COVERAGE_OUTPUT_FILE) $(CODE_COVERAGE_OUTPUT_FILE).tmp $(CODE_COVERAGE_OUTPUT_DIRECTORY) - -find . \( -name "*.gcda" -o -name "*.gcno" -o -name "*.gcov" \) -delete -'] - ], [ - [CODE_COVERAGE_RULES_CHECK=' - @echo "Need to reconfigure with --enable-code-coverage" -'] - CODE_COVERAGE_RULES_CAPTURE="$CODE_COVERAGE_RULES_CHECK" - CODE_COVERAGE_RULES_CLEAN='' - ]) - -[CODE_COVERAGE_RULES=' -# Code coverage -# -# Optional: -# - CODE_COVERAGE_DIRECTORY: Top-level directory for code coverage reporting. -# Multiple directories may be specified, separated by whitespace. -# (Default: $(top_builddir)) -# - CODE_COVERAGE_OUTPUT_FILE: Filename and path for the .info file generated -# by lcov for code coverage. (Default: -# $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage.info) -# - CODE_COVERAGE_OUTPUT_DIRECTORY: Directory for generated code coverage -# reports to be created. (Default: -# $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage) -# - CODE_COVERAGE_BRANCH_COVERAGE: Set to 1 to enforce branch coverage, -# set to 0 to disable it and leave empty to stay with the default. -# (Default: empty) -# - CODE_COVERAGE_LCOV_SHOPTS_DEFAULT: Extra options shared between both lcov -# instances. (Default: based on $CODE_COVERAGE_BRANCH_COVERAGE) -# - CODE_COVERAGE_LCOV_SHOPTS: Extra options to shared between both lcov -# instances. (Default: $CODE_COVERAGE_LCOV_SHOPTS_DEFAULT) -# - CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH: --gcov-tool pathtogcov -# - CODE_COVERAGE_LCOV_OPTIONS_DEFAULT: Extra options to pass to the -# collecting lcov instance. (Default: $CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH) -# - CODE_COVERAGE_LCOV_OPTIONS: Extra options to pass to the collecting lcov -# instance. (Default: $CODE_COVERAGE_LCOV_OPTIONS_DEFAULT) -# - CODE_COVERAGE_LCOV_RMOPTS_DEFAULT: Extra options to pass to the filtering -# lcov instance. (Default: empty) -# - CODE_COVERAGE_LCOV_RMOPTS: Extra options to pass to the filtering lcov -# instance. (Default: $CODE_COVERAGE_LCOV_RMOPTS_DEFAULT) -# - CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT: Extra options to pass to the -# genhtml instance. (Default: based on $CODE_COVERAGE_BRANCH_COVERAGE) -# - CODE_COVERAGE_GENHTML_OPTIONS: Extra options to pass to the genhtml -# instance. (Default: $CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT) -# - CODE_COVERAGE_IGNORE_PATTERN: Extra glob pattern of files to ignore -# -# The generated report will be titled using the $(PACKAGE_NAME) and -# $(PACKAGE_VERSION). In order to add the current git hash to the title, -# use the git-version-gen script, available online. - -# Optional variables -CODE_COVERAGE_DIRECTORY ?= $(top_builddir) -CODE_COVERAGE_OUTPUT_FILE ?= $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage.info -CODE_COVERAGE_OUTPUT_DIRECTORY ?= $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage -CODE_COVERAGE_BRANCH_COVERAGE ?= -CODE_COVERAGE_LCOV_SHOPTS_DEFAULT ?= $(if $(CODE_COVERAGE_BRANCH_COVERAGE),\ ---rc lcov_branch_coverage=$(CODE_COVERAGE_BRANCH_COVERAGE)) -CODE_COVERAGE_LCOV_SHOPTS ?= $(CODE_COVERAGE_LCOV_SHOPTS_DEFAULT) -CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH ?= --gcov-tool "$(GCOV)" -CODE_COVERAGE_LCOV_OPTIONS_DEFAULT ?= $(CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH) -CODE_COVERAGE_LCOV_OPTIONS ?= $(CODE_COVERAGE_LCOV_OPTIONS_DEFAULT) -CODE_COVERAGE_LCOV_RMOPTS_DEFAULT ?= -CODE_COVERAGE_LCOV_RMOPTS ?= $(CODE_COVERAGE_LCOV_RMOPTS_DEFAULT) -CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT ?=\ -$(if $(CODE_COVERAGE_BRANCH_COVERAGE),\ ---rc genhtml_branch_coverage=$(CODE_COVERAGE_BRANCH_COVERAGE)) -CODE_COVERAGE_GENHTML_OPTIONS ?= $(CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT) -CODE_COVERAGE_IGNORE_PATTERN ?= - -GITIGNOREFILES ?= -GITIGNOREFILES += $(CODE_COVERAGE_OUTPUT_FILE) $(CODE_COVERAGE_OUTPUT_DIRECTORY) - -code_coverage_v_lcov_cap = $(code_coverage_v_lcov_cap_$(V)) -code_coverage_v_lcov_cap_ = $(code_coverage_v_lcov_cap_$(AM_DEFAULT_VERBOSITY)) -code_coverage_v_lcov_cap_0 = @echo " LCOV --capture"\ - $(CODE_COVERAGE_OUTPUT_FILE); -code_coverage_v_lcov_ign = $(code_coverage_v_lcov_ign_$(V)) -code_coverage_v_lcov_ign_ = $(code_coverage_v_lcov_ign_$(AM_DEFAULT_VERBOSITY)) -code_coverage_v_lcov_ign_0 = @echo " LCOV --remove /tmp/*"\ - $(CODE_COVERAGE_IGNORE_PATTERN); -code_coverage_v_genhtml = $(code_coverage_v_genhtml_$(V)) -code_coverage_v_genhtml_ = $(code_coverage_v_genhtml_$(AM_DEFAULT_VERBOSITY)) -code_coverage_v_genhtml_0 = @echo " GEN " $(CODE_COVERAGE_OUTPUT_DIRECTORY); -code_coverage_quiet = $(code_coverage_quiet_$(V)) -code_coverage_quiet_ = $(code_coverage_quiet_$(AM_DEFAULT_VERBOSITY)) -code_coverage_quiet_0 = --quiet - -# sanitizes the test-name: replaces with underscores: dashes and dots -code_coverage_sanitize = $(subst -,_,$(subst .,_,$(1))) - -# Use recursive makes in order to ignore errors during check -check-code-coverage:'"$CODE_COVERAGE_RULES_CHECK"' - -# Capture code coverage data -code-coverage-capture: code-coverage-capture-hook'"$CODE_COVERAGE_RULES_CAPTURE"' - -# Hook rule executed before code-coverage-capture, overridable by the user -code-coverage-capture-hook: - -'"$CODE_COVERAGE_RULES_CLEAN"' - -A''M_DISTCHECK_CONFIGURE_FLAGS ?= -A''M_DISTCHECK_CONFIGURE_FLAGS += --disable-code-coverage - -.PHONY: check-code-coverage code-coverage-capture code-coverage-capture-hook code-coverage-clean -'] - - AC_SUBST([CODE_COVERAGE_RULES]) - m4_ifdef([_AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE([CODE_COVERAGE_RULES])]) -]) diff --git a/libs/harfbuzz/m4/ax_cxx_compile_stdcxx.m4 b/libs/harfbuzz/m4/ax_cxx_compile_stdcxx.m4 deleted file mode 100644 index 8b6df5a5d..000000000 --- a/libs/harfbuzz/m4/ax_cxx_compile_stdcxx.m4 +++ /dev/null @@ -1,982 +0,0 @@ -# =========================================================================== -# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional]) -# -# DESCRIPTION -# -# Check for baseline language coverage in the compiler for the specified -# version of the C++ standard. If necessary, add switches to CXX and -# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard) -# or '14' (for the C++14 standard). -# -# The second argument, if specified, indicates whether you insist on an -# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. -# -std=c++11). If neither is specified, you get whatever works, with -# preference for an extended mode. -# -# The third argument, if specified 'mandatory' or if left unspecified, -# indicates that baseline support for the specified C++ standard is -# required and that the macro should error out if no mode with that -# support is found. If specified 'optional', then configuration proceeds -# regardless, after defining HAVE_CXX${VERSION} if and only if a -# supporting mode is found. -# -# LICENSE -# -# Copyright (c) 2008 Benjamin Kosnik -# Copyright (c) 2012 Zack Weinberg -# Copyright (c) 2013 Roy Stogner -# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov -# Copyright (c) 2015 Paul Norman -# Copyright (c) 2015 Moritz Klammler -# Copyright (c) 2016 Krzesimir Nowak -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 7 - -dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro -dnl (serial version number 13). - -AX_REQUIRE_DEFINED([AC_MSG_WARN]) -AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl - m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"], - [$1], [14], [ax_cxx_compile_alternatives="14 1y"], - [$1], [17], [ax_cxx_compile_alternatives="17 1z"], - [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl - m4_if([$2], [], [], - [$2], [ext], [], - [$2], [noext], [], - [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl - m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true], - [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true], - [$3], [optional], [ax_cxx_compile_cxx$1_required=false], - [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])]) - AC_LANG_PUSH([C++])dnl - ac_success=no - AC_CACHE_CHECK(whether $CXX supports C++$1 features by default, - ax_cv_cxx_compile_cxx$1, - [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], - [ax_cv_cxx_compile_cxx$1=yes], - [ax_cv_cxx_compile_cxx$1=no])]) - if test x$ax_cv_cxx_compile_cxx$1 = xyes; then - ac_success=yes - fi - - m4_if([$2], [noext], [], [dnl - if test x$ac_success = xno; then - for alternative in ${ax_cxx_compile_alternatives}; do - switch="-std=gnu++${alternative}" - cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) - AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, - $cachevar, - [ac_save_CXX="$CXX" - CXX="$CXX $switch" - AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], - [eval $cachevar=yes], - [eval $cachevar=no]) - CXX="$ac_save_CXX"]) - if eval test x\$$cachevar = xyes; then - CXX="$CXX $switch" - if test -n "$CXXCPP" ; then - CXXCPP="$CXXCPP $switch" - fi - ac_success=yes - break - fi - done - fi]) - - m4_if([$2], [ext], [], [dnl - if test x$ac_success = xno; then - dnl HP's aCC needs +std=c++11 according to: - dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf - dnl Cray's crayCC needs "-h std=c++11" - for alternative in ${ax_cxx_compile_alternatives}; do - for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do - cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) - AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, - $cachevar, - [ac_save_CXX="$CXX" - CXX="$CXX $switch" - AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], - [eval $cachevar=yes], - [eval $cachevar=no]) - CXX="$ac_save_CXX"]) - if eval test x\$$cachevar = xyes; then - CXX="$CXX $switch" - if test -n "$CXXCPP" ; then - CXXCPP="$CXXCPP $switch" - fi - ac_success=yes - break - fi - done - if test x$ac_success = xyes; then - break - fi - done - fi]) - AC_LANG_POP([C++]) - if test x$ax_cxx_compile_cxx$1_required = xtrue; then - if test x$ac_success = xno; then - AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.]) - fi - fi - if test x$ac_success = xno; then - HAVE_CXX$1=0 - AC_MSG_NOTICE([No compiler with C++$1 support was found]) - else - HAVE_CXX$1=1 - AC_DEFINE(HAVE_CXX$1,1, - [define if the compiler supports basic C++$1 syntax]) - fi - AC_SUBST(HAVE_CXX$1) - m4_if([$1], [17], [AC_MSG_WARN([C++17 is not yet standardized, so the checks may change in incompatible ways anytime])]) -]) - - -dnl Test body for checking C++11 support - -m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11], - _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 -) - - -dnl Test body for checking C++14 support - -m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], - _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 - _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 -) - -m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17], - _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 - _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 - _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 -) - -dnl Tests for new features in C++11 - -m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ - -// If the compiler admits that it is not ready for C++11, why torture it? -// Hopefully, this will speed up the test. - -#ifndef __cplusplus - -#error "This is not a C++ compiler" - -#elif __cplusplus < 201103L - -#error "This is not a C++11 compiler" - -#else - -namespace cxx11 -{ - - namespace test_static_assert - { - - template - struct check - { - static_assert(sizeof(int) <= sizeof(T), "not big enough"); - }; - - } - - namespace test_final_override - { - - struct Base - { - virtual void f() {} - }; - - struct Derived : public Base - { - virtual void f() override {} - }; - - } - - namespace test_double_right_angle_brackets - { - - template < typename T > - struct check {}; - - typedef check single_type; - typedef check> double_type; - typedef check>> triple_type; - typedef check>>> quadruple_type; - - } - - namespace test_decltype - { - - int - f() - { - int a = 1; - decltype(a) b = 2; - return a + b; - } - - } - - namespace test_type_deduction - { - - template < typename T1, typename T2 > - struct is_same - { - static const bool value = false; - }; - - template < typename T > - struct is_same - { - static const bool value = true; - }; - - template < typename T1, typename T2 > - auto - add(T1 a1, T2 a2) -> decltype(a1 + a2) - { - return a1 + a2; - } - - int - test(const int c, volatile int v) - { - static_assert(is_same::value == true, ""); - static_assert(is_same::value == false, ""); - static_assert(is_same::value == false, ""); - auto ac = c; - auto av = v; - auto sumi = ac + av + 'x'; - auto sumf = ac + av + 1.0; - static_assert(is_same::value == true, ""); - static_assert(is_same::value == true, ""); - static_assert(is_same::value == true, ""); - static_assert(is_same::value == false, ""); - static_assert(is_same::value == true, ""); - return (sumf > 0.0) ? sumi : add(c, v); - } - - } - - namespace test_noexcept - { - - int f() { return 0; } - int g() noexcept { return 0; } - - static_assert(noexcept(f()) == false, ""); - static_assert(noexcept(g()) == true, ""); - - } - - namespace test_constexpr - { - - template < typename CharT > - unsigned long constexpr - strlen_c_r(const CharT *const s, const unsigned long acc) noexcept - { - return *s ? strlen_c_r(s + 1, acc + 1) : acc; - } - - template < typename CharT > - unsigned long constexpr - strlen_c(const CharT *const s) noexcept - { - return strlen_c_r(s, 0UL); - } - - static_assert(strlen_c("") == 0UL, ""); - static_assert(strlen_c("1") == 1UL, ""); - static_assert(strlen_c("example") == 7UL, ""); - static_assert(strlen_c("another\0example") == 7UL, ""); - - } - - namespace test_rvalue_references - { - - template < int N > - struct answer - { - static constexpr int value = N; - }; - - answer<1> f(int&) { return answer<1>(); } - answer<2> f(const int&) { return answer<2>(); } - answer<3> f(int&&) { return answer<3>(); } - - void - test() - { - int i = 0; - const int c = 0; - static_assert(decltype(f(i))::value == 1, ""); - static_assert(decltype(f(c))::value == 2, ""); - static_assert(decltype(f(0))::value == 3, ""); - } - - } - - namespace test_uniform_initialization - { - - struct test - { - static const int zero {}; - static const int one {1}; - }; - - static_assert(test::zero == 0, ""); - static_assert(test::one == 1, ""); - - } - - namespace test_lambdas - { - - void - test1() - { - auto lambda1 = [](){}; - auto lambda2 = lambda1; - lambda1(); - lambda2(); - } - - int - test2() - { - auto a = [](int i, int j){ return i + j; }(1, 2); - auto b = []() -> int { return '0'; }(); - auto c = [=](){ return a + b; }(); - auto d = [&](){ return c; }(); - auto e = [a, &b](int x) mutable { - const auto identity = [](int y){ return y; }; - for (auto i = 0; i < a; ++i) - a += b--; - return x + identity(a + b); - }(0); - return a + b + c + d + e; - } - - int - test3() - { - const auto nullary = [](){ return 0; }; - const auto unary = [](int x){ return x; }; - using nullary_t = decltype(nullary); - using unary_t = decltype(unary); - const auto higher1st = [](nullary_t f){ return f(); }; - const auto higher2nd = [unary](nullary_t f1){ - return [unary, f1](unary_t f2){ return f2(unary(f1())); }; - }; - return higher1st(nullary) + higher2nd(nullary)(unary); - } - - } - - namespace test_variadic_templates - { - - template - struct sum; - - template - struct sum - { - static constexpr auto value = N0 + sum::value; - }; - - template <> - struct sum<> - { - static constexpr auto value = 0; - }; - - static_assert(sum<>::value == 0, ""); - static_assert(sum<1>::value == 1, ""); - static_assert(sum<23>::value == 23, ""); - static_assert(sum<1, 2>::value == 3, ""); - static_assert(sum<5, 5, 11>::value == 21, ""); - static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); - - } - - // https://stackoverflow.com/questions/13728184/template-aliases-and-sfinae - // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function - // because of this. - namespace test_template_alias_sfinae - { - - struct foo {}; - - template - using member = typename T::member_type; - - template - void func(...) {} - - template - void func(member*) {} - - void test(); - - void test() { func(0); } - - } - -} // namespace cxx11 - -#endif // __cplusplus >= 201103L - -]]) - - -dnl Tests for new features in C++14 - -m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[ - -// If the compiler admits that it is not ready for C++14, why torture it? -// Hopefully, this will speed up the test. - -#ifndef __cplusplus - -#error "This is not a C++ compiler" - -#elif __cplusplus < 201402L - -#error "This is not a C++14 compiler" - -#else - -namespace cxx14 -{ - - namespace test_polymorphic_lambdas - { - - int - test() - { - const auto lambda = [](auto&&... args){ - const auto istiny = [](auto x){ - return (sizeof(x) == 1UL) ? 1 : 0; - }; - const int aretiny[] = { istiny(args)... }; - return aretiny[0]; - }; - return lambda(1, 1L, 1.0f, '1'); - } - - } - - namespace test_binary_literals - { - - constexpr auto ivii = 0b0000000000101010; - static_assert(ivii == 42, "wrong value"); - - } - - namespace test_generalized_constexpr - { - - template < typename CharT > - constexpr unsigned long - strlen_c(const CharT *const s) noexcept - { - auto length = 0UL; - for (auto p = s; *p; ++p) - ++length; - return length; - } - - static_assert(strlen_c("") == 0UL, ""); - static_assert(strlen_c("x") == 1UL, ""); - static_assert(strlen_c("test") == 4UL, ""); - static_assert(strlen_c("another\0test") == 7UL, ""); - - } - - namespace test_lambda_init_capture - { - - int - test() - { - auto x = 0; - const auto lambda1 = [a = x](int b){ return a + b; }; - const auto lambda2 = [a = lambda1(x)](){ return a; }; - return lambda2(); - } - - } - - namespace test_digit_separators - { - - constexpr auto ten_million = 100'000'000; - static_assert(ten_million == 100000000, ""); - - } - - namespace test_return_type_deduction - { - - auto f(int& x) { return x; } - decltype(auto) g(int& x) { return x; } - - template < typename T1, typename T2 > - struct is_same - { - static constexpr auto value = false; - }; - - template < typename T > - struct is_same - { - static constexpr auto value = true; - }; - - int - test() - { - auto x = 0; - static_assert(is_same::value, ""); - static_assert(is_same::value, ""); - return x; - } - - } - -} // namespace cxx14 - -#endif // __cplusplus >= 201402L - -]]) - - -dnl Tests for new features in C++17 - -m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[ - -// If the compiler admits that it is not ready for C++17, why torture it? -// Hopefully, this will speed up the test. - -#ifndef __cplusplus - -#error "This is not a C++ compiler" - -#elif __cplusplus <= 201402L - -#error "This is not a C++17 compiler" - -#else - -#if defined(__clang__) - #define REALLY_CLANG -#else - #if defined(__GNUC__) - #define REALLY_GCC - #endif -#endif - -#include -#include -#include - -namespace cxx17 -{ - -#if !defined(REALLY_CLANG) - namespace test_constexpr_lambdas - { - - // TODO: test it with clang++ from git - - constexpr int foo = [](){return 42;}(); - - } -#endif // !defined(REALLY_CLANG) - - namespace test::nested_namespace::definitions - { - - } - - namespace test_fold_expression - { - - template - int multiply(Args... args) - { - return (args * ... * 1); - } - - template - bool all(Args... args) - { - return (args && ...); - } - - } - - namespace test_extended_static_assert - { - - static_assert (true); - - } - - namespace test_auto_brace_init_list - { - - auto foo = {5}; - auto bar {5}; - - static_assert(std::is_same, decltype(foo)>::value); - static_assert(std::is_same::value); - } - - namespace test_typename_in_template_template_parameter - { - - template typename X> struct D; - - } - - namespace test_fallthrough_nodiscard_maybe_unused_attributes - { - - int f1() - { - return 42; - } - - [[nodiscard]] int f2() - { - [[maybe_unused]] auto unused = f1(); - - switch (f1()) - { - case 17: - f1(); - [[fallthrough]]; - case 42: - f1(); - } - return f1(); - } - - } - - namespace test_extended_aggregate_initialization - { - - struct base1 - { - int b1, b2 = 42; - }; - - struct base2 - { - base2() { - b3 = 42; - } - int b3; - }; - - struct derived : base1, base2 - { - int d; - }; - - derived d1 {{1, 2}, {}, 4}; // full initialization - derived d2 {{}, {}, 4}; // value-initialized bases - - } - - namespace test_general_range_based_for_loop - { - - struct iter - { - int i; - - int& operator* () - { - return i; - } - - const int& operator* () const - { - return i; - } - - iter& operator++() - { - ++i; - return *this; - } - }; - - struct sentinel - { - int i; - }; - - bool operator== (const iter& i, const sentinel& s) - { - return i.i == s.i; - } - - bool operator!= (const iter& i, const sentinel& s) - { - return !(i == s); - } - - struct range - { - iter begin() const - { - return {0}; - } - - sentinel end() const - { - return {5}; - } - }; - - void f() - { - range r {}; - - for (auto i : r) - { - [[maybe_unused]] auto v = i; - } - } - - } - - namespace test_lambda_capture_asterisk_this_by_value - { - - struct t - { - int i; - int foo() - { - return [*this]() - { - return i; - }(); - } - }; - - } - - namespace test_enum_class_construction - { - - enum class byte : unsigned char - {}; - - byte foo {42}; - - } - - namespace test_constexpr_if - { - - template - int f () - { - if constexpr(cond) - { - return 13; - } - else - { - return 42; - } - } - - } - - namespace test_selection_statement_with_initializer - { - - int f() - { - return 13; - } - - int f2() - { - if (auto i = f(); i > 0) - { - return 3; - } - - switch (auto i = f(); i + 4) - { - case 17: - return 2; - - default: - return 1; - } - } - - } - -#if !defined(REALLY_CLANG) - namespace test_template_argument_deduction_for_class_templates - { - - // TODO: test it with clang++ from git - - template - struct pair - { - pair (T1 p1, T2 p2) - : m1 {p1}, - m2 {p2} - {} - - T1 m1; - T2 m2; - }; - - void f() - { - [[maybe_unused]] auto p = pair{13, 42u}; - } - - } -#endif // !defined(REALLY_CLANG) - - namespace test_non_type_auto_template_parameters - { - - template - struct B - {}; - - B<5> b1; - B<'a'> b2; - - } - -#if !defined(REALLY_CLANG) - namespace test_structured_bindings - { - - // TODO: test it with clang++ from git - - int arr[2] = { 1, 2 }; - std::pair pr = { 1, 2 }; - - auto f1() -> int(&)[2] - { - return arr; - } - - auto f2() -> std::pair& - { - return pr; - } - - struct S - { - int x1 : 2; - volatile double y1; - }; - - S f3() - { - return {}; - } - - auto [ x1, y1 ] = f1(); - auto& [ xr1, yr1 ] = f1(); - auto [ x2, y2 ] = f2(); - auto& [ xr2, yr2 ] = f2(); - const auto [ x3, y3 ] = f3(); - - } -#endif // !defined(REALLY_CLANG) - -#if !defined(REALLY_CLANG) - namespace test_exception_spec_type_system - { - - // TODO: test it with clang++ from git - - struct Good {}; - struct Bad {}; - - void g1() noexcept; - void g2(); - - template - Bad - f(T*, T*); - - template - Good - f(T1*, T2*); - - static_assert (std::is_same_v); - - } -#endif // !defined(REALLY_CLANG) - - namespace test_inline_variables - { - - template void f(T) - {} - - template inline T g(T) - { - return T{}; - } - - template<> inline void f<>(int) - {} - - template<> int g<>(int) - { - return 5; - } - - } - -} // namespace cxx17 - -#endif // __cplusplus <= 201402L - -]]) diff --git a/libs/harfbuzz/m4/ax_pthread.m4 b/libs/harfbuzz/m4/ax_pthread.m4 deleted file mode 100644 index 5fbf9fe0d..000000000 --- a/libs/harfbuzz/m4/ax_pthread.m4 +++ /dev/null @@ -1,485 +0,0 @@ -# =========================================================================== -# https://www.gnu.org/software/autoconf-archive/ax_pthread.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) -# -# DESCRIPTION -# -# This macro figures out how to build C programs using POSIX threads. It -# sets the PTHREAD_LIBS output variable to the threads library and linker -# flags, and the PTHREAD_CFLAGS output variable to any special C compiler -# flags that are needed. (The user can also force certain compiler -# flags/libs to be tested by setting these environment variables.) -# -# Also sets PTHREAD_CC to any special C compiler that is needed for -# multi-threaded programs (defaults to the value of CC otherwise). (This -# is necessary on AIX to use the special cc_r compiler alias.) -# -# NOTE: You are assumed to not only compile your program with these flags, -# but also to link with them as well. For example, you might link with -# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS -# -# If you are only building threaded programs, you may wish to use these -# variables in your default LIBS, CFLAGS, and CC: -# -# LIBS="$PTHREAD_LIBS $LIBS" -# CFLAGS="$CFLAGS $PTHREAD_CFLAGS" -# CC="$PTHREAD_CC" -# -# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant -# has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to -# that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). -# -# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the -# PTHREAD_PRIO_INHERIT symbol is defined when compiling with -# PTHREAD_CFLAGS. -# -# ACTION-IF-FOUND is a list of shell commands to run if a threads library -# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it -# is not found. If ACTION-IF-FOUND is not specified, the default action -# will define HAVE_PTHREAD. -# -# Please let the authors know if this macro fails on any platform, or if -# you have any other suggestions or comments. This macro was based on work -# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help -# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by -# Alejandro Forero Cuervo to the autoconf macro repository. We are also -# grateful for the helpful feedback of numerous users. -# -# Updated for Autoconf 2.68 by Daniel Richard G. -# -# LICENSE -# -# Copyright (c) 2008 Steven G. Johnson -# Copyright (c) 2011 Daniel Richard G. -# -# This program is free software: you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation, either version 3 of the License, or (at your -# option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General -# Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program. If not, see . -# -# As a special exception, the respective Autoconf Macro's copyright owner -# gives unlimited permission to copy, distribute and modify the configure -# scripts that are the output of Autoconf when processing the Macro. You -# need not follow the terms of the GNU General Public License when using -# or distributing such scripts, even though portions of the text of the -# Macro appear in them. The GNU General Public License (GPL) does govern -# all other use of the material that constitutes the Autoconf Macro. -# -# This special exception to the GPL applies to versions of the Autoconf -# Macro released by the Autoconf Archive. When you make and distribute a -# modified version of the Autoconf Macro, you may extend this special -# exception to the GPL to apply to your modified version as well. - -#serial 24 - -AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) -AC_DEFUN([AX_PTHREAD], [ -AC_REQUIRE([AC_CANONICAL_HOST]) -AC_REQUIRE([AC_PROG_CC]) -AC_REQUIRE([AC_PROG_SED]) -AC_LANG_PUSH([C]) -ax_pthread_ok=no - -# We used to check for pthread.h first, but this fails if pthread.h -# requires special compiler flags (e.g. on Tru64 or Sequent). -# It gets checked for in the link test anyway. - -# First of all, check if the user has set any of the PTHREAD_LIBS, -# etcetera environment variables, and if threads linking works using -# them: -if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then - ax_pthread_save_CC="$CC" - ax_pthread_save_CFLAGS="$CFLAGS" - ax_pthread_save_LIBS="$LIBS" - AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"]) - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - LIBS="$PTHREAD_LIBS $LIBS" - AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS]) - AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes]) - AC_MSG_RESULT([$ax_pthread_ok]) - if test "x$ax_pthread_ok" = "xno"; then - PTHREAD_LIBS="" - PTHREAD_CFLAGS="" - fi - CC="$ax_pthread_save_CC" - CFLAGS="$ax_pthread_save_CFLAGS" - LIBS="$ax_pthread_save_LIBS" -fi - -# We must check for the threads library under a number of different -# names; the ordering is very important because some systems -# (e.g. DEC) have both -lpthread and -lpthreads, where one of the -# libraries is broken (non-POSIX). - -# Create a list of thread flags to try. Items starting with a "-" are -# C compiler flags, and other items are library names, except for "none" -# which indicates that we try without any flags at all, and "pthread-config" -# which is a program returning the flags for the Pth emulation library. - -ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" - -# The ordering *is* (sometimes) important. Some notes on the -# individual items follow: - -# pthreads: AIX (must check this before -lpthread) -# none: in case threads are in libc; should be tried before -Kthread and -# other compiler flags to prevent continual compiler warnings -# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) -# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64 -# (Note: HP C rejects this with "bad form for `-t' option") -# -pthreads: Solaris/gcc (Note: HP C also rejects) -# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it -# doesn't hurt to check since this sometimes defines pthreads and -# -D_REENTRANT too), HP C (must be checked before -lpthread, which -# is present but should not be used directly; and before -mthreads, -# because the compiler interprets this as "-mt" + "-hreads") -# -mthreads: Mingw32/gcc, Lynx/gcc -# pthread: Linux, etcetera -# --thread-safe: KAI C++ -# pthread-config: use pthread-config program (for GNU Pth library) - -case $host_os in - - freebsd*) - - # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) - # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) - - ax_pthread_flags="-kthread lthread $ax_pthread_flags" - ;; - - hpux*) - - # From the cc(1) man page: "[-mt] Sets various -D flags to enable - # multi-threading and also sets -lpthread." - - ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags" - ;; - - openedition*) - - # IBM z/OS requires a feature-test macro to be defined in order to - # enable POSIX threads at all, so give the user a hint if this is - # not set. (We don't define these ourselves, as they can affect - # other portions of the system API in unpredictable ways.) - - AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING], - [ -# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS) - AX_PTHREAD_ZOS_MISSING -# endif - ], - [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])]) - ;; - - solaris*) - - # On Solaris (at least, for some versions), libc contains stubbed - # (non-functional) versions of the pthreads routines, so link-based - # tests will erroneously succeed. (N.B.: The stubs are missing - # pthread_cleanup_push, or rather a function called by this macro, - # so we could check for that, but who knows whether they'll stub - # that too in a future libc.) So we'll check first for the - # standard Solaris way of linking pthreads (-mt -lpthread). - - ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags" - ;; -esac - -# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC) - -AS_IF([test "x$GCC" = "xyes"], - [ax_pthread_flags="-pthread -pthreads $ax_pthread_flags"]) - -# The presence of a feature test macro requesting re-entrant function -# definitions is, on some systems, a strong hint that pthreads support is -# correctly enabled - -case $host_os in - darwin* | hpux* | linux* | osf* | solaris*) - ax_pthread_check_macro="_REENTRANT" - ;; - - aix*) - ax_pthread_check_macro="_THREAD_SAFE" - ;; - - *) - ax_pthread_check_macro="--" - ;; -esac -AS_IF([test "x$ax_pthread_check_macro" = "x--"], - [ax_pthread_check_cond=0], - [ax_pthread_check_cond="!defined($ax_pthread_check_macro)"]) - -# Are we compiling with Clang? - -AC_CACHE_CHECK([whether $CC is Clang], - [ax_cv_PTHREAD_CLANG], - [ax_cv_PTHREAD_CLANG=no - # Note that Autoconf sets GCC=yes for Clang as well as GCC - if test "x$GCC" = "xyes"; then - AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG], - [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */ -# if defined(__clang__) && defined(__llvm__) - AX_PTHREAD_CC_IS_CLANG -# endif - ], - [ax_cv_PTHREAD_CLANG=yes]) - fi - ]) -ax_pthread_clang="$ax_cv_PTHREAD_CLANG" - -ax_pthread_clang_warning=no - -# Clang needs special handling, because older versions handle the -pthread -# option in a rather... idiosyncratic way - -if test "x$ax_pthread_clang" = "xyes"; then - - # Clang takes -pthread; it has never supported any other flag - - # (Note 1: This will need to be revisited if a system that Clang - # supports has POSIX threads in a separate library. This tends not - # to be the way of modern systems, but it's conceivable.) - - # (Note 2: On some systems, notably Darwin, -pthread is not needed - # to get POSIX threads support; the API is always present and - # active. We could reasonably leave PTHREAD_CFLAGS empty. But - # -pthread does define _REENTRANT, and while the Darwin headers - # ignore this macro, third-party headers might not.) - - PTHREAD_CFLAGS="-pthread" - PTHREAD_LIBS= - - ax_pthread_ok=yes - - # However, older versions of Clang make a point of warning the user - # that, in an invocation where only linking and no compilation is - # taking place, the -pthread option has no effect ("argument unused - # during compilation"). They expect -pthread to be passed in only - # when source code is being compiled. - # - # Problem is, this is at odds with the way Automake and most other - # C build frameworks function, which is that the same flags used in - # compilation (CFLAGS) are also used in linking. Many systems - # supported by AX_PTHREAD require exactly this for POSIX threads - # support, and in fact it is often not straightforward to specify a - # flag that is used only in the compilation phase and not in - # linking. Such a scenario is extremely rare in practice. - # - # Even though use of the -pthread flag in linking would only print - # a warning, this can be a nuisance for well-run software projects - # that build with -Werror. So if the active version of Clang has - # this misfeature, we search for an option to squash it. - - AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread], - [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG], - [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown - # Create an alternate version of $ac_link that compiles and - # links in two steps (.c -> .o, .o -> exe) instead of one - # (.c -> exe), because the warning occurs only in the second - # step - ax_pthread_save_ac_link="$ac_link" - ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g' - ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"` - ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)" - ax_pthread_save_CFLAGS="$CFLAGS" - for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do - AS_IF([test "x$ax_pthread_try" = "xunknown"], [break]) - CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS" - ac_link="$ax_pthread_save_ac_link" - AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], - [ac_link="$ax_pthread_2step_ac_link" - AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], - [break]) - ]) - done - ac_link="$ax_pthread_save_ac_link" - CFLAGS="$ax_pthread_save_CFLAGS" - AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no]) - ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try" - ]) - - case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in - no | unknown) ;; - *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;; - esac - -fi # $ax_pthread_clang = yes - -if test "x$ax_pthread_ok" = "xno"; then -for ax_pthread_try_flag in $ax_pthread_flags; do - - case $ax_pthread_try_flag in - none) - AC_MSG_CHECKING([whether pthreads work without any flags]) - ;; - - -mt,pthread) - AC_MSG_CHECKING([whether pthreads work with -mt -lpthread]) - PTHREAD_CFLAGS="-mt" - PTHREAD_LIBS="-lpthread" - ;; - - -*) - AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag]) - PTHREAD_CFLAGS="$ax_pthread_try_flag" - ;; - - pthread-config) - AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) - AS_IF([test "x$ax_pthread_config" = "xno"], [continue]) - PTHREAD_CFLAGS="`pthread-config --cflags`" - PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" - ;; - - *) - AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag]) - PTHREAD_LIBS="-l$ax_pthread_try_flag" - ;; - esac - - ax_pthread_save_CFLAGS="$CFLAGS" - ax_pthread_save_LIBS="$LIBS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - LIBS="$PTHREAD_LIBS $LIBS" - - # Check for various functions. We must include pthread.h, - # since some functions may be macros. (On the Sequent, we - # need a special flag -Kthread to make this header compile.) - # We check for pthread_join because it is in -lpthread on IRIX - # while pthread_create is in libc. We check for pthread_attr_init - # due to DEC craziness with -lpthreads. We check for - # pthread_cleanup_push because it is one of the few pthread - # functions on Solaris that doesn't have a non-functional libc stub. - # We try pthread_create on general principles. - - AC_LINK_IFELSE([AC_LANG_PROGRAM([#include -# if $ax_pthread_check_cond -# error "$ax_pthread_check_macro must be defined" -# endif - static void routine(void *a) { a = 0; } - static void *start_routine(void *a) { return a; }], - [pthread_t th; pthread_attr_t attr; - pthread_create(&th, 0, start_routine, 0); - pthread_join(th, 0); - pthread_attr_init(&attr); - pthread_cleanup_push(routine, 0); - pthread_cleanup_pop(0) /* ; */])], - [ax_pthread_ok=yes], - []) - - CFLAGS="$ax_pthread_save_CFLAGS" - LIBS="$ax_pthread_save_LIBS" - - AC_MSG_RESULT([$ax_pthread_ok]) - AS_IF([test "x$ax_pthread_ok" = "xyes"], [break]) - - PTHREAD_LIBS="" - PTHREAD_CFLAGS="" -done -fi - -# Various other checks: -if test "x$ax_pthread_ok" = "xyes"; then - ax_pthread_save_CFLAGS="$CFLAGS" - ax_pthread_save_LIBS="$LIBS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - LIBS="$PTHREAD_LIBS $LIBS" - - # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. - AC_CACHE_CHECK([for joinable pthread attribute], - [ax_cv_PTHREAD_JOINABLE_ATTR], - [ax_cv_PTHREAD_JOINABLE_ATTR=unknown - for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do - AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], - [int attr = $ax_pthread_attr; return attr /* ; */])], - [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break], - []) - done - ]) - AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \ - test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \ - test "x$ax_pthread_joinable_attr_defined" != "xyes"], - [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], - [$ax_cv_PTHREAD_JOINABLE_ATTR], - [Define to necessary symbol if this constant - uses a non-standard name on your system.]) - ax_pthread_joinable_attr_defined=yes - ]) - - AC_CACHE_CHECK([whether more special flags are required for pthreads], - [ax_cv_PTHREAD_SPECIAL_FLAGS], - [ax_cv_PTHREAD_SPECIAL_FLAGS=no - case $host_os in - solaris*) - ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS" - ;; - esac - ]) - AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \ - test "x$ax_pthread_special_flags_added" != "xyes"], - [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS" - ax_pthread_special_flags_added=yes]) - - AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], - [ax_cv_PTHREAD_PRIO_INHERIT], - [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], - [[int i = PTHREAD_PRIO_INHERIT;]])], - [ax_cv_PTHREAD_PRIO_INHERIT=yes], - [ax_cv_PTHREAD_PRIO_INHERIT=no]) - ]) - AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \ - test "x$ax_pthread_prio_inherit_defined" != "xyes"], - [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.]) - ax_pthread_prio_inherit_defined=yes - ]) - - CFLAGS="$ax_pthread_save_CFLAGS" - LIBS="$ax_pthread_save_LIBS" - - # More AIX lossage: compile with *_r variant - if test "x$GCC" != "xyes"; then - case $host_os in - aix*) - AS_CASE(["x/$CC"], - [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], - [#handle absolute path differently from PATH based program lookup - AS_CASE(["x$CC"], - [x/*], - [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])], - [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])]) - ;; - esac - fi -fi - -test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" - -AC_SUBST([PTHREAD_LIBS]) -AC_SUBST([PTHREAD_CFLAGS]) -AC_SUBST([PTHREAD_CC]) - -# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: -if test "x$ax_pthread_ok" = "xyes"; then - ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) - : -else - ax_pthread_ok=no - $2 -fi -AC_LANG_POP -])dnl AX_PTHREAD diff --git a/libs/harfbuzz/meson.build b/libs/harfbuzz/meson.build index b80679d3a..5a02b3bb2 100644 --- a/libs/harfbuzz/meson.build +++ b/libs/harfbuzz/meson.build @@ -1,43 +1,61 @@ project('harfbuzz', 'c', 'cpp', meson_version: '>= 0.55.0', - version: '5.3.1', + version: '10.1.0', default_options: [ - 'cpp_rtti=false', # Just to support msvc, we are passing -fno-exceptions also anyway + '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 ], ) +glib_min_version = '>= 2.30.0' +cairo_min_version = '>= 1.10.0' +chafa_min_version = '>= 1.6.0' +icu_min_version = '>= 49.0' +graphite2_min_version = '>= 1.2.0' + +freetype_min_version_actual = '>= 2.4.2' +freetype_min_version = '>= 12.0.6' # Corresponds to `freetype_min_version_actual` + hb_version_arr = meson.project_version().split('.') hb_version_major = hb_version_arr[0].to_int() hb_version_minor = hb_version_arr[1].to_int() hb_version_micro = hb_version_arr[2].to_int() # libtool versioning -hb_version_int = hb_version_major*10000 + hb_version_minor*100 + hb_version_micro +hb_version_int = 60000 + hb_version_major*100 + hb_version_minor*10 + hb_version_micro hb_libtool_version_info = '@0@:0:@0@'.format(hb_version_int) pkgmod = import('pkgconfig') cpp = meson.get_compiler('cpp') null_dep = dependency('', required: false) +# 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.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 + add_project_arguments('/std:c++14', language : 'cpp') + endif +endif + if cpp.get_argument_syntax() == 'msvc' # Ignore several spurious warnings for things HarfBuzz does very commonly. # If a warning is completely useless and spammy, use '/wdXXXX' to suppress it # If a warning is harmless but hard to fix, use '/woXXXX' so it's shown once # NOTE: Only add warnings here if you are sure they're spurious msvc_args = [ - '/wd4018', # implicit signed/unsigned conversion - '/wd4146', # unary minus on unsigned (beware INT_MIN) '/wd4244', # lossy type conversion (e.g. double -> int) - '/wd4305', # truncating type conversion (e.g. double -> float) + '/bigobj', # hb-subset.cc -- compile error C1128: number of sections exceeded object file format limit cpp.get_supported_arguments(['/utf-8']), # set the input encoding to utf-8 ] add_project_arguments(msvc_args, language: ['c', 'cpp']) # Disable SAFESEH with MSVC for libs that use external deps that are built with MinGW # noseh_link_args = ['/SAFESEH:NO'] - # disable exception handling - add_project_arguments(['/EHs-', '/EHc-'], language: 'cpp') endif add_project_link_arguments(cpp.get_supported_link_arguments([ @@ -71,51 +89,105 @@ check_headers = [ ] check_funcs = [ - ['atexit'], - ['mprotect'], - ['sysconf'], - ['getpagesize'], - ['mmap'], - ['isatty'], - ['uselocale'], - ['newlocale'], + ['atexit', {'prefix': '#include '}], + ['mprotect', {'prefix': '#include '}], + ['sysconf', {'prefix': '#include '}], + ['getpagesize', {'prefix': '#include '}], + ['mmap', {'prefix': '#include '}], + ['isatty', {'prefix': '#include '}], + ['uselocale', {'prefix': '#include '}], + ['newlocale', {'prefix': '#include '}], + ['sincosf', {'prefix': '#define _GNU_SOURCE\n#include '}], ] m_dep = cpp.find_library('m', required: false) - -# Try pkgconfig name -freetype_dep = dependency('freetype2', required: false) -if not freetype_dep.found() - # Try cmake name - freetype_dep = dependency('freetype', required: false) -endif -if not freetype_dep.found() - # Subproject fallback, `allow_fallback: true` means the fallback will be - # tried even if the freetype option is set to `auto`. +if meson.version().version_compare('>=0.60.0') + # Sadly, FreeType's versioning schemes are different between pkg-config and CMake + # pkg-config: freetype2, cmake: Freetype freetype_dep = dependency('freetype2', - required: get_option('freetype'), - default_options: ['harfbuzz=disabled'], - allow_fallback: true) + version: freetype_min_version, + method: 'pkg-config', + required: false, + allow_fallback: false) + if not freetype_dep.found() + freetype_dep = dependency('FreeType', + version: freetype_min_version_actual, + method: 'cmake', + 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_dep = dependency('freetype2', + version: freetype_min_version, + method: 'pkg-config', + required: get_option('freetype'), + default_options: ['harfbuzz=disabled'], + allow_fallback: true) + endif + endif endif -glib_dep = dependency('glib-2.0', required: get_option('glib')) -gobject_dep = dependency('gobject-2.0', required: get_option('gobject')) -graphite2_dep = dependency('graphite2', required: get_option('graphite2')) -graphite_dep = dependency('graphite2', required: get_option('graphite')) - -# Try pkgconfig name -icu_dep = dependency('icu-uc', required: false) -if not icu_dep.found() - # Try cmake name - icu_dep = dependency('ICU', - required: false, - components: 'uc', - method: 'cmake') +glib_dep = dependency('glib-2.0', version: glib_min_version, required: get_option('glib')) +gobject_dep = dependency('gobject-2.0', version: glib_min_version, required: get_option('gobject')) +graphite2_dep = dependency('graphite2', version: graphite2_min_version, required: get_option('graphite2')) +graphite_dep = dependency('graphite2', version: graphite2_min_version, required: get_option('graphite')) +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')) + +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 not icu_dep.found() - # Subproject fallback if icu option is enabled - icu_dep = dependency('icu-uc', required: get_option('icu')) + +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' + add_project_arguments(cpp17_arg, language: 'cpp') endif if icu_dep.found() and icu_dep.type_name() == 'pkgconfig' @@ -128,8 +200,8 @@ endif cairo_dep = null_dep cairo_ft_dep = null_dep if not get_option('cairo').disabled() - cairo_dep = dependency('cairo', required: false) - cairo_ft_dep = dependency('cairo-ft', required: false) + cairo_dep = dependency('cairo', version: cairo_min_version, required: false) + cairo_ft_dep = dependency('cairo-ft', version: cairo_min_version, required: false) if (not cairo_dep.found() and cpp.get_argument_syntax() == 'msvc' and @@ -147,12 +219,13 @@ if not get_option('cairo').disabled() # dependency cycle here because we have configured freetype2 above with # harfbuzz support disabled, so when cairo will lookup freetype2 dependency # it will be forced to use that one. - cairo_dep = dependency('cairo', required: get_option('cairo')) - cairo_ft_dep = dependency('cairo-ft', required: get_option('cairo')) + cairo_dep = dependency('cairo', version: cairo_min_version, required: get_option('cairo')) + cairo_ft_required = get_option('cairo').enabled() and get_option('freetype').enabled() + cairo_ft_dep = dependency('cairo-ft', version: cairo_min_version, required: cairo_ft_required) endif endif -chafa_dep = dependency('chafa', version: '>= 1.6.0', required: get_option('chafa')) +chafa_dep = dependency('chafa', version: chafa_min_version, required: get_option('chafa')) conf = configuration_data() incconfig = include_directories('.') @@ -175,10 +248,19 @@ endif if cairo_dep.found() conf.set('HAVE_CAIRO', 1) + check_cairo_funcs = [ + ['cairo_user_font_face_set_render_color_glyph_func', {'deps': cairo_dep}], + ['cairo_font_options_get_custom_palette_color', {'deps': cairo_dep}], + ['cairo_user_scaled_font_get_foreground_source', {'deps': cairo_dep}], + ] + if cairo_dep.type_name() == 'internal' - conf.set('HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC', 1) + foreach func: check_cairo_funcs + name = func[0] + conf.set('HAVE_@0@'.format(name.to_upper()), 1) + endforeach else - check_funcs += [['cairo_user_font_face_set_render_color_glyph_func', {'deps': cairo_dep}]] + check_funcs += check_cairo_funcs endif endif @@ -190,6 +272,11 @@ if chafa_dep.found() conf.set('HAVE_CHAFA', 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"') +endif + if graphite2_dep.found() or graphite_dep.found() conf.set('HAVE_GRAPHITE2', 1) endif @@ -304,11 +391,12 @@ foreach check : check_funcs opts = check.get(1, {}) link_withs = opts.get('link_with', []) check_deps = opts.get('deps', []) + check_prefix = opts.get('prefix', '') extra_deps = [] found = true # First try without linking - found = cpp.has_function(name, dependencies: check_deps) + found = cpp.has_function(name, prefix: check_prefix, dependencies: check_deps) if not found and link_withs.length() > 0 found = true @@ -323,7 +411,7 @@ foreach check : check_funcs endforeach if found - found = cpp.has_function(name, dependencies: check_deps + extra_deps) + found = cpp.has_function(name, prefix: check_prefix, dependencies: check_deps + extra_deps) endif endif @@ -333,8 +421,31 @@ foreach check : check_funcs endif endforeach +# CMake support (package install dir) + +# Equivalent to configure_package_config_file(INSTALL_DESTINATION ...), see +# https://cmake.org/cmake/help/latest/module/CMakePackageConfigHelpers.html#command:configure_package_config_file. +# In certain unusual packaging layouts such as Nixpkgs, the Harfbuzz package +# is installed into two Nix store paths, "out" and "dev", where "out" contains +# libraries only (i.e. lib/libharfbuzz.so) and "dev" contains development +# files, i.e. include and lib/cmake. If CMake package files are installed to +# "out", Nixpkgs will move them to "dev", which breaks assumptions about +# our file paths. Since we need to figure out relative install paths here +# to make a relocatable package, we do need to know the final path of our +# CMake files to calculate the correct relative paths. +# Of course, this still defaults to $libdir/cmake if unset, which works for +# most packaging layouts. +cmake_package_install_dir = get_option('cmakepackagedir') + +if cmake_package_install_dir == '' + cmake_package_install_dir = get_option('libdir') / 'cmake' +endif + subdir('src') -subdir('util') + +if not get_option('utilities').disabled() + subdir('util') +endif if not get_option('tests').disabled() subdir('test') @@ -350,6 +461,9 @@ endif configure_file(output: 'config.h', configuration: conf) +alias_target('lib', libharfbuzz) +alias_target('libs', libharfbuzz, libharfbuzz_subset) + build_summary = { 'Directories': {'prefix': get_option('prefix'), @@ -357,6 +471,7 @@ build_summary = { 'libdir': get_option('libdir'), 'includedir': get_option('includedir'), 'datadir': get_option('datadir'), + 'cmakepackagedir': cmake_package_install_dir }, 'Unicode callbacks (you want at least one)': {'Builtin': true, @@ -364,7 +479,8 @@ build_summary = { 'ICU': conf.get('HAVE_ICU', 0) == 1, }, 'Font callbacks (the more the merrier)': - {'FreeType': conf.get('HAVE_FREETYPE', 0) == 1, + {'Builtin' : true, + 'FreeType': conf.get('HAVE_FREETYPE', 0) == 1, }, 'Dependencies used for command-line utilities': {'Cairo': conf.get('HAVE_CAIRO', 0) == 1, @@ -372,15 +488,17 @@ build_summary = { }, 'Additional shapers': {'Graphite2': conf.get('HAVE_GRAPHITE2', 0) == 1, + 'WebAssembly (experimental)': conf.get('HAVE_WASM', 0) == 1, }, 'Platform shapers (not normally needed)': {'CoreText': conf.get('HAVE_CORETEXT', 0) == 1, - 'DirectWrite': conf.get('HAVE_DIRECTWRITE', 0) == 1, + 'DirectWrite (experimental)': conf.get('HAVE_DIRECTWRITE', 0) == 1, 'GDI/Uniscribe': (conf.get('HAVE_GDI', 0) == 1) and (conf.get('HAVE_UNISCRIBE', 0) == 1), }, 'Other features': {'Documentation': conf.get('HAVE_GTK_DOC', 0) == 1, 'GObject bindings': conf.get('HAVE_GOBJECT', 0) == 1, + 'Cairo integration': conf.get('HAVE_CAIRO', 0) == 1, 'Introspection': conf.get('HAVE_INTROSPECTION', 0) == 1, 'Experimental APIs': conf.get('HB_EXPERIMENTAL_API', 0) == 1, }, diff --git a/libs/harfbuzz/meson_options.txt b/libs/harfbuzz/meson_options.txt index 9ebba72c6..c53cf45fc 100644 --- a/libs/harfbuzz/meson_options.txt +++ b/libs/harfbuzz/meson_options.txt @@ -21,6 +21,8 @@ option('directwrite', type: 'feature', value: 'disabled', 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', + description: 'Enable WebAssembly shaper backend (experimental)') # Common feature options option('tests', type: 'feature', value: 'enabled', yield: true, @@ -29,14 +31,24 @@ option('introspection', type: 'feature', value: 'auto', yield: true, description: 'Generate gobject-introspection bindings (.gir/.typelib files)') option('docs', type: 'feature', value: 'auto', yield: true, description: 'Generate documentation with gtk-doc') +option('doc_tests', type: 'boolean', value: false, + description: 'Run gtkdoc-check tests') +option('utilities', type: 'feature', value: 'enabled', yield: true, + description: 'Build harfbuzz utils') option('benchmark', type: 'feature', value: 'disabled', description: 'Enable benchmark tests') option('icu_builtin', type: 'boolean', value: false, description: 'Don\'t separate ICU support as harfbuzz-icu module') +option('with_libstdcxx', type: 'boolean', value: false, + description: 'Allow linking with libstdc++') option('experimental_api', type: 'boolean', value: false, description: 'Enable experimental APIs') option('ragel_subproject', type: 'boolean', value: false, description: 'Build Ragel subproject if no suitable version is found') option('fuzzer_ldflags', type: 'string', description: 'Extra LDFLAGS used during linking of fuzzing binaries') + +# Install directory options +option('cmakepackagedir', type: 'string', + description: 'CMake package configuration install directory') diff --git a/libs/harfbuzz/mingw-configure.sh b/libs/harfbuzz/mingw-configure.sh deleted file mode 100644 index 496cae291..000000000 --- a/libs/harfbuzz/mingw-configure.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/sh - -case $1 in - i686 | x86_64) ;; - *) echo "Usage: $0 i686|x86_64" >&2; exit 1 ;; -esac - -target=$1-w64-mingw32 -shift - -exec "$(dirname "$0")"/configure \ - --build=`../config.guess` \ - --host=$target \ - --prefix=$HOME/.local/$target \ - CC= \ - CXX= \ - CPP= \ - LD= \ - CFLAGS="-static-libgcc" \ - CXXFLAGS="-O2 -static-libgcc -static-libstdc++" \ - CPPFLAGS="-I$HOME/.local/$target/include" \ - LDFLAGS=-L$HOME/.local/$target/lib \ - PKG_CONFIG_LIBDIR=$HOME/.local/$target/lib/pkgconfig:/usr/$target/sys-root/mingw/lib/pkgconfig/ \ - PKG_CONFIG_PATH=$HOME/.local/$target/share/pkgconfig:/usr/$target/sys-root/mingw/share/pkgconfig/ \ - PATH=$HOME/.local/$target/bin:/usr/$target/sys-root/mingw/bin:/usr/$target/bin:$PATH \ - --without-icu \ - --with-gdi \ - --with-uniscribe \ - --with-directwrite=auto \ - "$@" diff --git a/libs/harfbuzz/perf/Makefile.am b/libs/harfbuzz/perf/Makefile.am deleted file mode 100644 index 1e67b9231..000000000 --- a/libs/harfbuzz/perf/Makefile.am +++ /dev/null @@ -1,23 +0,0 @@ -# Process this file with automake to produce Makefile.in - -NULL = -EXTRA_DIST = -SUBDIRS = - -EXTRA_DIST += \ - meson.build \ - benchmark-font.cc \ - benchmark-map.cc \ - benchmark-ot.cc \ - benchmark-set.cc \ - benchmark-shape.cc \ - benchmark-subset.cc \ - fonts \ - texts \ - $(NULL) - -# Convenience targets: -lib: - @$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib - --include $(top_srcdir)/git.mk diff --git a/libs/harfbuzz/perf/benchmark-font.cc b/libs/harfbuzz/perf/benchmark-font.cc index 98b6310d2..5fb7bd2bb 100644 --- a/libs/harfbuzz/perf/benchmark-font.cc +++ b/libs/harfbuzz/perf/benchmark-font.cc @@ -1,17 +1,4 @@ -#include "benchmark/benchmark.h" -#include -#include - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "hb.h" -#include "hb-ot.h" -#ifdef HAVE_FREETYPE -#include "hb-ft.h" -#endif - +#include "hb-benchmark.hh" #define SUBSET_FONT_BASE_PATH "test/subset/data/fonts/" @@ -21,7 +8,8 @@ struct test_input_t const char *font_path; } default_tests[] = { - {true , SUBSET_FONT_BASE_PATH "Roboto-Regular.ttf"}, + {false, SUBSET_FONT_BASE_PATH "Roboto-Regular.ttf"}, + {true , SUBSET_FONT_BASE_PATH "RobotoFlex-Variable.ttf"}, {false, SUBSET_FONT_BASE_PATH "SourceSansPro-Regular.otf"}, {true , SUBSET_FONT_BASE_PATH "AdobeVFPrototype.otf"}, {true , SUBSET_FONT_BASE_PATH "SourceSerifVariable-Roman.ttf"}, @@ -33,30 +21,52 @@ struct test_input_t static test_input_t *tests = default_tests; static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]); -enum backend_t { HARFBUZZ, FREETYPE }; +enum backend_t { HARFBUZZ, FREETYPE, CORETEXT }; enum operation_t { nominal_glyphs, glyph_h_advances, glyph_extents, - glyph_shape, + draw_glyph, + paint_glyph, + load_face_and_shape, }; static void -_hb_move_to (hb_draw_funcs_t *, void *, hb_draw_state_t *, float, float, void *) {} +_hb_move_to (hb_draw_funcs_t *, void *draw_data, hb_draw_state_t *, float x, float y, void *) +{ + float &i = * (float *) draw_data; + i += x + y; +} static void -_hb_line_to (hb_draw_funcs_t *, void *, hb_draw_state_t *, float, float, void *) {} +_hb_line_to (hb_draw_funcs_t *, void *draw_data, hb_draw_state_t *, float x, float y, void *) +{ + float &i = * (float *) draw_data; + i += x + y; +} -//static void -//_hb_quadratic_to (hb_draw_funcs_t *, void *, hb_draw_state_t *, float, float, float, float, void *) {} +static void +_hb_quadratic_to (hb_draw_funcs_t *, void *draw_data, hb_draw_state_t *, float cx, float cy, float x, float y, void *) +{ + float &i = * (float *) draw_data; + i += cx + cy + x + y; +} static void -_hb_cubic_to (hb_draw_funcs_t *, void *, hb_draw_state_t *, float, float, float, float, float, float, void *) {} +_hb_cubic_to (hb_draw_funcs_t *, void *draw_data, hb_draw_state_t *, float cx1, float cy1, float cx2, float cy2, float x, float y, void *) +{ + float &i = * (float *) draw_data; + i += cx1 + cy1 + cx2 + cy2 + x + y; +} static void -_hb_close_path (hb_draw_funcs_t *, void *, hb_draw_state_t *, void *) {} +_hb_close_path (hb_draw_funcs_t *, void *draw_data, hb_draw_state_t *, void *) +{ + float &i = * (float *) draw_data; + i += 1.0; +} static hb_draw_funcs_t * _draw_funcs_create (void) @@ -64,7 +74,7 @@ _draw_funcs_create (void) hb_draw_funcs_t *draw_funcs = hb_draw_funcs_create (); hb_draw_funcs_set_move_to_func (draw_funcs, _hb_move_to, nullptr, nullptr); hb_draw_funcs_set_line_to_func (draw_funcs, _hb_line_to, nullptr, nullptr); - //hb_draw_funcs_set_quadratic_to_func (draw_funcs, _hb_quadratic_to, nullptr, nullptr); + hb_draw_funcs_set_quadratic_to_func (draw_funcs, _hb_quadratic_to, nullptr, nullptr); hb_draw_funcs_set_cubic_to_func (draw_funcs, _hb_cubic_to, nullptr, nullptr); hb_draw_funcs_set_close_path_func (draw_funcs, _hb_close_path, nullptr, nullptr); return draw_funcs; @@ -77,10 +87,8 @@ static void BM_Font (benchmark::State &state, hb_font_t *font; unsigned num_glyphs; { - hb_blob_t *blob = hb_blob_create_from_file_or_fail (test_input.font_path); - assert (blob); - hb_face_t *face = hb_face_create (blob, 0); - hb_blob_destroy (blob); + hb_face_t *face = hb_benchmark_face_create_from_file_or_fail (test_input.font_path, 0); + assert (face); num_glyphs = hb_face_get_glyph_count (face); font = hb_font_create (face); hb_face_destroy (face); @@ -101,6 +109,12 @@ static void BM_Font (benchmark::State &state, 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; } @@ -158,14 +172,67 @@ static void BM_Font (benchmark::State &state, hb_font_get_glyph_extents (font, gid, &extents); break; } - case glyph_shape: + case draw_glyph: { hb_draw_funcs_t *draw_funcs = _draw_funcs_create (); for (auto _ : state) + { + float i = 0; for (unsigned gid = 0; gid < num_glyphs; ++gid) - hb_font_get_glyph_shape (font, gid, draw_funcs, nullptr); - break; + hb_font_draw_glyph (font, gid, draw_funcs, &i); + } hb_draw_funcs_destroy (draw_funcs); + break; + } + case paint_glyph: + { + hb_paint_funcs_t *paint_funcs = hb_paint_funcs_create (); + for (auto _ : state) + { + for (unsigned gid = 0; gid < num_glyphs; ++gid) + hb_font_paint_glyph (font, gid, paint_funcs, nullptr, 0, 0); + } + hb_paint_funcs_destroy (paint_funcs); + break; + } + case load_face_and_shape: + { + for (auto _ : state) + { + hb_face_t *face = hb_benchmark_face_create_from_file_or_fail (test_input.font_path, 0); + assert (face); + hb_font_t *font = hb_font_create (face); + hb_face_destroy (face); + + switch (backend) + { + 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 (); + hb_buffer_add_utf8 (buffer, " ", -1, 0, -1); + hb_buffer_guess_segment_properties (buffer); + + hb_shape (font, buffer, nullptr, 0); + + hb_buffer_destroy (buffer); + hb_font_destroy (font); + } + break; } } @@ -208,6 +275,9 @@ static void test_operation (operation_t op, 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 } } @@ -233,7 +303,9 @@ int main(int argc, char** argv) TEST_OPERATION (nominal_glyphs, benchmark::kMicrosecond); TEST_OPERATION (glyph_h_advances, benchmark::kMicrosecond); TEST_OPERATION (glyph_extents, benchmark::kMicrosecond); - TEST_OPERATION (glyph_shape, benchmark::kMicrosecond); + TEST_OPERATION (draw_glyph, benchmark::kMicrosecond); + TEST_OPERATION (paint_glyph, benchmark::kMillisecond); + TEST_OPERATION (load_face_and_shape, benchmark::kMicrosecond); #undef TEST_OPERATION diff --git a/libs/harfbuzz/perf/benchmark-map.cc b/libs/harfbuzz/perf/benchmark-map.cc index f278a0c94..fbdf17c9a 100644 --- a/libs/harfbuzz/perf/benchmark-map.cc +++ b/libs/harfbuzz/perf/benchmark-map.cc @@ -1,22 +1,22 @@ -/* - * Benchmarks for hb_map_t operations. - */ -#include "benchmark/benchmark.h" +#include "hb-benchmark.hh" -#include -#include -#include "hb.h" - -void RandomMap(unsigned size, hb_map_t* out) { +void RandomMap(unsigned size, hb_map_t* out, hb_set_t* key_sample) { hb_map_clear(out); + unsigned sample_denom = 1; + if (size > 10000) + sample_denom = size / 10000; + srand(size); for (unsigned i = 0; i < size; i++) { while (true) { hb_codepoint_t next = rand(); if (hb_map_has (out, next)) continue; - hb_map_set (out, next, rand ()); + hb_codepoint_t val = rand(); + if (key_sample && val % sample_denom == 0) + hb_set_add (key_sample, next); + hb_map_set (out, next, val); break; } } @@ -27,16 +27,20 @@ static void BM_MapInsert(benchmark::State& state) { unsigned map_size = state.range(0); hb_map_t* original = hb_map_create (); - RandomMap(map_size, original); + RandomMap(map_size, original, nullptr); assert(hb_map_get_population(original) == map_size); - auto needle = map_size / 2; - auto v = 0; + unsigned mask = 1; + while (mask < map_size) + mask <<= 1; + mask--; + + auto needle = 0u; for (auto _ : state) { // TODO(garretrieger): create a copy of the original map. // Needs a hb_map_copy(..) in public api. - hb_map_set (original, needle++, v++); + hb_map_set (original, needle++ & mask, 1); } hb_map_destroy(original); @@ -44,12 +48,12 @@ static void BM_MapInsert(benchmark::State& state) { BENCHMARK(BM_MapInsert) ->Range(1 << 4, 1 << 20); -/* Single value lookup on map of various sizes. */ -static void BM_MapLookup(benchmark::State& state) { +/* Single value lookup on map of various sizes where the key is not present. */ +static void BM_MapLookupMiss(benchmark::State& state) { unsigned map_size = state.range(0); hb_map_t* original = hb_map_create (); - RandomMap(map_size, original); + RandomMap(map_size, original, nullptr); assert(hb_map_get_population(original) == map_size); auto needle = map_size / 2; @@ -61,7 +65,38 @@ static void BM_MapLookup(benchmark::State& state) { hb_map_destroy(original); } -BENCHMARK(BM_MapLookup) +BENCHMARK(BM_MapLookupMiss) + ->Range(1 << 4, 1 << 20); // Map size + +/* Single value lookup on map of various sizes. */ +static void BM_MapLookupHit(benchmark::State& state) { + unsigned map_size = state.range(0); + + hb_map_t* original = hb_map_create (); + hb_set_t* key_set = hb_set_create (); + RandomMap(map_size, original, key_set); + assert(hb_map_get_population(original) == map_size); + + unsigned num_keys = hb_set_get_population (key_set); + hb_codepoint_t* key_array = + (hb_codepoint_t*) calloc (num_keys, sizeof(hb_codepoint_t)); + + hb_codepoint_t cp = HB_SET_VALUE_INVALID; + unsigned i = 0; + while (hb_set_next (key_set, &cp)) + key_array[i++] = cp; + + i = 0; + for (auto _ : state) { + benchmark::DoNotOptimize( + hb_map_get (original, key_array[i++ % num_keys])); + } + + hb_set_destroy (key_set); + free (key_array); + hb_map_destroy(original); +} +BENCHMARK(BM_MapLookupHit) ->Range(1 << 4, 1 << 20); // Map size diff --git a/libs/harfbuzz/perf/benchmark-ot.cc b/libs/harfbuzz/perf/benchmark-ot.cc index c79c384a0..812c0da4b 100644 --- a/libs/harfbuzz/perf/benchmark-ot.cc +++ b/libs/harfbuzz/perf/benchmark-ot.cc @@ -1,9 +1,4 @@ -/* - * Benchmarks for hb_set_t operations. - */ -#include "benchmark/benchmark.h" - -#include "hb-ot.h" +#include "hb-benchmark.hh" static void BM_hb_ot_tags_from_script_and_language (benchmark::State& state, hb_script_t script, diff --git a/libs/harfbuzz/perf/benchmark-set.cc b/libs/harfbuzz/perf/benchmark-set.cc index c170acfc0..098082186 100644 --- a/libs/harfbuzz/perf/benchmark-set.cc +++ b/libs/harfbuzz/perf/benchmark-set.cc @@ -1,11 +1,4 @@ -/* - * Benchmarks for hb_set_t operations. - */ -#include "benchmark/benchmark.h" - -#include -#include -#include "hb.h" +#include "hb-benchmark.hh" void RandomSet(unsigned size, unsigned max_value, hb_set_t* out) { hb_set_clear(out); diff --git a/libs/harfbuzz/perf/benchmark-shape.cc b/libs/harfbuzz/perf/benchmark-shape.cc index 626a59777..490eda2b9 100644 --- a/libs/harfbuzz/perf/benchmark-shape.cc +++ b/libs/harfbuzz/perf/benchmark-shape.cc @@ -1,17 +1,4 @@ -#include "benchmark/benchmark.h" -#include - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include "hb.h" -#include "hb-ot.h" -#ifdef HAVE_FREETYPE -#include "hb-ft.h" -#endif +#include "hb-benchmark.hh" #define SUBSET_FONT_BASE_PATH "test/subset/data/fonts/" @@ -27,10 +14,18 @@ struct test_input_t "perf/texts/fa-thelittleprince.txt", false}, + {"perf/fonts/NotoNastaliqUrdu-Regular.ttf", + "perf/texts/fa-words.txt", + false}, + {"perf/fonts/Amiri-Regular.ttf", "perf/texts/fa-thelittleprince.txt", false}, + {SUBSET_FONT_BASE_PATH "NotoSansDevanagari-Regular.ttf", + "perf/texts/hi-words.txt", + false}, + {"perf/fonts/Roboto-Regular.ttf", "perf/texts/en-thelittleprince.txt", false}, @@ -56,10 +51,8 @@ static void BM_Shape (benchmark::State &state, { hb_font_t *font; { - hb_blob_t *blob = hb_blob_create_from_file_or_fail (input.font_path); - assert (blob); - hb_face_t *face = hb_face_create (blob, 0); - hb_blob_destroy (blob); + hb_face_t *face = hb_benchmark_face_create_from_file_or_fail (input.font_path, 0); + assert (face); font = hb_font_create (face); hb_face_destroy (face); } diff --git a/libs/harfbuzz/perf/benchmark-subset.cc b/libs/harfbuzz/perf/benchmark-subset.cc index 0451c11d8..b86150a37 100644 --- a/libs/harfbuzz/perf/benchmark-subset.cc +++ b/libs/harfbuzz/perf/benchmark-subset.cc @@ -1,18 +1,9 @@ -#include "benchmark/benchmark.h" -#include -#include - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "hb-subset.h" - +#include "hb-benchmark.hh" enum operation_t { - subset_codepoints, subset_glyphs, + subset_unicodes, instance, }; @@ -46,6 +37,13 @@ _mplus_instance_opts[] = {HB_TAG ('w', 'g', 'h', 't'), 800.f}, }; +static const axis_location_t +_fraunces_partial_instance_opts[] = +{ + {HB_TAG ('S', 'O', 'F', 'T'), 75.0f}, + {HB_TAG ('W', 'O', 'N', 'K'), 0.75f}, +}; + template static inline unsigned int ARRAY_LEN (const Type (&)[n]) { return n; } @@ -54,25 +52,31 @@ static inline unsigned int ARRAY_LEN (const Type (&)[n]) { return n; } struct test_input_t { const char *font_path; - const unsigned max_subset_size; + unsigned max_subset_size; const axis_location_t *instance_opts; - const unsigned num_instance_opts; -} tests[] = + unsigned num_instance_opts; +} default_tests[] = { - {SUBSET_FONT_BASE_PATH "Roboto-Regular.ttf", 4000, nullptr, 0}, - {SUBSET_FONT_BASE_PATH "Amiri-Regular.ttf", 4000, nullptr, 0}, - {SUBSET_FONT_BASE_PATH "NotoNastaliqUrdu-Regular.ttf", 1000, nullptr, 0}, + {SUBSET_FONT_BASE_PATH "Roboto-Regular.ttf", 1000, nullptr, 0}, + {SUBSET_FONT_BASE_PATH "Amiri-Regular.ttf", 4096, nullptr, 0}, + {SUBSET_FONT_BASE_PATH "NotoNastaliqUrdu-Regular.ttf", 1400, nullptr, 0}, {SUBSET_FONT_BASE_PATH "NotoSansDevanagari-Regular.ttf", 1000, nullptr, 0}, {SUBSET_FONT_BASE_PATH "Mplus1p-Regular.ttf", 10000, nullptr, 0}, {SUBSET_FONT_BASE_PATH "SourceHanSans-Regular_subset.otf", 10000, nullptr, 0}, {SUBSET_FONT_BASE_PATH "SourceSansPro-Regular.otf", 2000, nullptr, 0}, + {SUBSET_FONT_BASE_PATH "AdobeVFPrototype.otf", 300, nullptr, 0}, {SUBSET_FONT_BASE_PATH "MPLUS1-Variable.ttf", 6000, _mplus_instance_opts, ARRAY_LEN (_mplus_instance_opts)}, {SUBSET_FONT_BASE_PATH "RobotoFlex-Variable.ttf", 900, _roboto_flex_instance_opts, ARRAY_LEN (_roboto_flex_instance_opts)}, + {SUBSET_FONT_BASE_PATH "Fraunces.ttf", 900, _fraunces_partial_instance_opts, ARRAY_LEN (_fraunces_partial_instance_opts)}, #if 0 {"perf/fonts/NotoSansCJKsc-VF.ttf", 100000}, #endif }; +static test_input_t *tests = default_tests; +static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]); + + void AddCodepoints(const hb_set_t* codepoints_in_font, unsigned subset_size, hb_subset_input_t* input) @@ -92,7 +96,12 @@ void AddGlyphs(unsigned num_glyphs_in_font, { auto *glyphs = hb_subset_input_glyph_set (input); for (unsigned i = 0; i < subset_size && i < num_glyphs_in_font; i++) { - // TODO(garretrieger): pick randomly. + if (i + 1 == subset_size && + hb_subset_input_get_flags (input) & HB_SUBSET_FLAGS_RETAIN_GIDS) + { + hb_set_add (glyphs, num_glyphs_in_font - 1); + continue; + } hb_set_add (glyphs, i); } } @@ -101,38 +110,58 @@ void AddGlyphs(unsigned num_glyphs_in_font, // the subsetting operations. static hb_face_t* preprocess_face(hb_face_t* face) { - #ifdef HB_EXPERIMENTAL_API hb_face_t* new_face = hb_subset_preprocess(face); hb_face_destroy(face); return new_face; - #else - return face; - #endif } +static hb_face_t *cached_face; + +static void +free_cached_face (void) +{ + hb_face_destroy (cached_face); + cached_face = nullptr; +} + + /* benchmark for subsetting a font */ static void BM_subset (benchmark::State &state, operation_t operation, - const test_input_t &test_input) + const test_input_t &test_input, + bool retain_gids) { unsigned subset_size = state.range(0); - hb_face_t *face; + hb_face_t *face = nullptr; + + static const char *cached_font_path; + + if (!cached_font_path || strcmp (cached_font_path, test_input.font_path)) { - hb_blob_t *blob = hb_blob_create_from_file_or_fail (test_input.font_path); - assert (blob); - face = hb_face_create (blob, 0); - hb_blob_destroy (blob); + face = hb_benchmark_face_create_from_file_or_fail (test_input.font_path, 0); + assert (face); face = preprocess_face (face); + + if (cached_face) + hb_face_destroy (cached_face); + + cached_face = hb_face_reference (face); + cached_font_path = test_input.font_path; } + else + face = hb_face_reference (cached_face); hb_subset_input_t* input = hb_subset_input_create_or_fail (); assert (input); + if (retain_gids) + hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_RETAIN_GIDS); + switch (operation) { - case subset_codepoints: + case subset_unicodes: { hb_set_t* all_codepoints = hb_set_create (); hb_face_collect_unicodes (face, all_codepoints); @@ -149,19 +178,19 @@ static void BM_subset (benchmark::State &state, break; case instance: -#ifdef HB_EXPERIMENTAL_API { hb_set_t* all_codepoints = hb_set_create (); hb_face_collect_unicodes (face, all_codepoints); AddCodepoints(all_codepoints, subset_size, input); hb_set_destroy (all_codepoints); + hb_subset_input_set_flags(input, hb_subset_input_get_flags(input) | HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS); + for (unsigned i = 0; i < test_input.num_instance_opts; i++) hb_subset_input_pin_axis_location (input, face, test_input.instance_opts[i].axis_tag, test_input.instance_opts[i].axis_value); } -#endif break; } @@ -178,6 +207,7 @@ static void BM_subset (benchmark::State &state, static void test_subset (operation_t op, const char *op_name, + bool retain_gids, benchmark::TimeUnit time_unit, const test_input_t &test_input) { @@ -186,36 +216,61 @@ static void test_subset (operation_t op, char name[1024] = "BM_subset/"; strcat (name, op_name); - strcat (name, strrchr (test_input.font_path, '/')); + strcat (name, "/"); + const char *p = strrchr (test_input.font_path, '/'); + strcat (name, p ? p + 1 : test_input.font_path); + if (retain_gids) + strcat (name, "/retaingids"); - benchmark::RegisterBenchmark (name, BM_subset, op, test_input) + benchmark::RegisterBenchmark (name, BM_subset, op, test_input, retain_gids) ->Range(10, test_input.max_subset_size) ->Unit(time_unit); } static void test_operation (operation_t op, const char *op_name, + const test_input_t *tests, + unsigned num_tests, benchmark::TimeUnit time_unit) { - for (auto& test_input : tests) + for (unsigned i = 0; i < num_tests; i++) { - test_subset (op, op_name, time_unit, test_input); + auto& test_input = tests[i]; + test_subset (op, op_name, true, time_unit, test_input); + test_subset (op, op_name, false, time_unit, test_input); } } int main(int argc, char** argv) { -#define TEST_OPERATION(op, time_unit) test_operation (op, #op, time_unit) + benchmark::Initialize(&argc, argv); - TEST_OPERATION (subset_glyphs, benchmark::kMillisecond); - TEST_OPERATION (subset_codepoints, benchmark::kMillisecond); -#ifdef HB_EXPERIMENTAL_API - TEST_OPERATION (instance, benchmark::kMillisecond); +#ifndef HB_NO_ATEXIT + atexit (free_cached_face); #endif + if (argc > 1) + { + num_tests = (argc - 1) / 2; + tests = (test_input_t *) calloc (num_tests, sizeof (test_input_t)); + for (unsigned i = 0; i < num_tests; i++) + { + tests[i].font_path = argv[1 + i * 2]; + tests[i].max_subset_size = atoi (argv[2 + i * 2]); + } + } + +#define TEST_OPERATION(op, time_unit) test_operation (op, #op, tests, num_tests, time_unit) + + TEST_OPERATION (subset_glyphs, benchmark::kMicrosecond); + TEST_OPERATION (subset_unicodes, benchmark::kMicrosecond); + TEST_OPERATION (instance, benchmark::kMicrosecond); + #undef TEST_OPERATION - benchmark::Initialize(&argc, argv); benchmark::RunSpecifiedBenchmarks(); benchmark::Shutdown(); + + if (tests != default_tests) + free (tests); } diff --git a/libs/harfbuzz/perf/hb-benchmark.hh b/libs/harfbuzz/perf/hb-benchmark.hh new file mode 100644 index 000000000..12d61f19d --- /dev/null +++ b/libs/harfbuzz/perf/hb-benchmark.hh @@ -0,0 +1,76 @@ +/* + * Copyright © 2024 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Author(s): Behdad Esfahbod + */ + +#ifndef HB_BENCHMARK_HH +#define HB_BENCHMARK_HH + +#include + +#include +#include + +#include +#ifdef HAVE_FREETYPE +#include +#endif +#ifdef HAVE_CORETEXT +#include +#endif + +#include + +#include +#include +#include + + +HB_BEGIN_DECLS + +static inline hb_face_t * +hb_benchmark_face_create_from_file_or_fail (const char *font_path, + unsigned face_index) +{ + 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 + +#endif /* HB_BENCHMARK_HH */ diff --git a/libs/harfbuzz/perf/meson.build b/libs/harfbuzz/perf/meson.build index ae122f439..92164e3ba 100644 --- a/libs/harfbuzz/perf/meson.build +++ b/libs/harfbuzz/perf/meson.build @@ -1,62 +1,24 @@ google_benchmark = subproject('google-benchmark') google_benchmark_dep = google_benchmark.get_variable('google_benchmark_dep') -benchmark('benchmark-font', executable('benchmark-font', 'benchmark-font.cc', - dependencies: [ - google_benchmark_dep, freetype_dep, - ], - cpp_args: [], - include_directories: [incconfig, incsrc], - link_with: [libharfbuzz], - install: false, -), workdir: meson.current_source_dir() / '..', timeout: 100) +benchmarks = [ + 'benchmark-font.cc', + 'benchmark-map.cc', + 'benchmark-ot.cc', + 'benchmark-set.cc', + 'benchmark-shape.cc', + 'benchmark-subset.cc', +] -benchmark('benchmark-map', executable('benchmark-map', 'benchmark-map.cc', - dependencies: [ - google_benchmark_dep, - ], - cpp_args: [], - include_directories: [incconfig, incsrc], - link_with: [libharfbuzz], - install: false, -), workdir: meson.current_source_dir() / '..', timeout: 100) - -benchmark('benchmark-ot', executable('benchmark-ot', 'benchmark-ot.cc', - dependencies: [ - google_benchmark_dep, - ], - cpp_args: [], - include_directories: [incconfig, incsrc], - link_with: [libharfbuzz], - install: false, -), workdir: meson.current_source_dir() / '..', timeout: 100) - -benchmark('benchmark-set', executable('benchmark-set', 'benchmark-set.cc', - dependencies: [ - google_benchmark_dep, - ], - cpp_args: [], - include_directories: [incconfig, incsrc], - link_with: [libharfbuzz], - install: false, -), workdir: meson.current_source_dir() / '..', timeout: 100) - -benchmark('benchmark-shape', executable('benchmark-shape', 'benchmark-shape.cc', - dependencies: [ - google_benchmark_dep, freetype_dep, - ], - cpp_args: [], - include_directories: [incconfig, incsrc], - link_with: [libharfbuzz], - install: false, -), workdir: meson.current_source_dir() / '..', timeout: 100) - -benchmark('benchmark-subset', executable('benchmark-subset', 'benchmark-subset.cc', - dependencies: [ - google_benchmark_dep, - ], - cpp_args: [], - include_directories: [incconfig, incsrc], - link_with: [libharfbuzz, libharfbuzz_subset], - install: false, -), workdir: meson.current_source_dir() / '..', timeout: 100) +foreach source : benchmarks + benchmark_name = source.split('.')[0] + benchmark(benchmark_name, executable(benchmark_name, source, + dependencies: [ + google_benchmark_dep, freetype_dep, coretext_deps, + ], + cpp_args: [], + include_directories: [incconfig, incsrc], + link_with: [libharfbuzz, libharfbuzz_subset], + install: false, + ), workdir: meson.current_source_dir() / '..', timeout: 100) +endforeach diff --git a/libs/harfbuzz/perf/run.sh b/libs/harfbuzz/perf/run.sh deleted file mode 100644 index c7dc6e0c2..000000000 --- a/libs/harfbuzz/perf/run.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -CXX=clang++ -FONT=fonts/NotoNastaliqUrdu-Regular.ttf -TEXT=texts/fa-monologue.txt - -$CXX ../util/hb-shape.cc ../util/options.cc ../src/harfbuzz.cc \ - -lm -fno-rtti -fno-exceptions -fno-omit-frame-pointer -DHB_NO_MT \ - -I../src $FLAGS $SOURCES \ - -DPACKAGE_NAME='""' -DPACKAGE_VERSION='""' \ - -DHAVE_GLIB $(pkg-config --cflags --libs glib-2.0) \ - -o hb-shape -g -O2 # -O3 \ - #-march=native -mtune=native \ - #-Rpass=loop-vectorize -Rpass-missed=loop-vectorize \ - #-Rpass-analysis=loop-vectorize -fsave-optimization-record - -# -march=native: enable all vector instructions current CPU can offer -# -Rpass*: https://llvm.org/docs/Vectorizers.html#diagnostics - -#sudo rm capture.syscap > /dev/null -#sysprof-cli -c "./a.out $@" -#sysprof capture.syscap - -perf stat ./hb-shape -o /dev/null $FONT --text-file $TEXT --num-iterations=100 --font-funcs=ot -#perf record -g ./hb-shape -O '' -o /dev/null $FONT --text-file $TEXT --num-iterations=100 --font-funcs=ot -#perf report -g diff --git a/libs/harfbuzz/perf/texts/duployan.txt b/libs/harfbuzz/perf/texts/duployan.txt new file mode 100644 index 000000000..f330fc909 --- /dev/null +++ b/libs/harfbuzz/perf/texts/duployan.txt @@ -0,0 +1,27 @@ +𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰅𛱄‌𛰂𛱁 𛱛𛰆𛰑𛱁𛰋 𛰃𛱚𛰚 + +𛱇𛰣 𛰂𛱆 𛰆𛱄𛰉𛰅𛰋𛱁𛰄𛰃 + +𛱁𛰆𛱇𛰅𛰜 𛰅𛱄𛰈 𛱊𛱁‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛱛‌𛰅𛱛𛰅 𛰜𛱇𛱇‌𛰜𛱇𛰙 𛰅𛱄‌𛰂𛱁 𛰣𛱇‌𛰚𛱛𛰅 + +𛰅𛰆𛱁𛰜‌𛰅𛱁 𛱜‌𛱜 𛰅𛱄‌𛰂𛱁 𛱛𛰆𛰑𛱁𛰋 𛰃𛱚𛰚 𛱆‌𛰚𛱁‌𛰃𛱁𛱆 𛰅𛱄‌𛰂𛱁 𛰜𛰅𛱂𛱆 𛰜𛰃𛱂‌𛰆𛱄͏͏͏, 𛱞𛰅 𛰃𛰆𛱛𛰜 𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱁𛰅‌𛰜𛰃𛱂 𛰙𛱁‌𛰙𛱛𛰅 𛰙𛱇𛰙‌𛰆𛱛𛰜 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜; 𛰂𛱆 𛰚𛱁𛱋‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛰚𛱁‌𛱞‌𛰃𛰅𛱁, 𛰂𛱛͏͏͏𛰜 𛰚𛱁𛱋‌𛰅𛱁 𛰚𛱁‌𛰚𛱇𛰣 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛱇𛰆𛱇𛰂 𛰅𛱄‌𛰂𛱁 𛰂𛱁‌𛱊𛱁 𛰂𛱆 𛱜‌𛱜 𛰅𛱁‌𛰅𛱜 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜. 𛰅𛱁‌𛰅𛱜 𛰂𛱛͏͏͏𛰜 𛱆𛰂‌𛰜𛱛𛰃 𛱛‌𛰅𛱛𛰅 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜. 𛰅𛱁‌𛰚𛱁‌𛱞 𛱆𛰅‌𛰃𛱂 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜: 𛱛‌𛰅𛱛𛰅 𛰚𛰜𛱁𛱆‌𛰅𛱁 𛱇𛰆𛱄͏͏͏ 𛰚𛱁‌𛰚𛱇𛰣. 𛱁‌𛱊𛱁𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰚𛱇𛰙 𛰅𛱄‌𛰂𛱁 𛱇𛰛𛱇𛰂𛰃 𛱇𛰆𛱇‌𛰀𛱇. 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛰅𛱁‌𛰃𛱂 𛱛‌𛰅𛱛𛰅 𛱁𛰚‌𛰅𛱁‌𛰃𛱇 𛰃𛱚𛰚 𛰙𛱇𛰋𛱄𛱆 𛰂𛱆 𛱄͏͏͏𛰄𛱆𛰋. 𛱛‌𛰅𛱛𛰅 𛰃𛱂‌𛱇𛱇 𛰅𛱄‌𛰂𛱁 𛰜𛰃𛱇𛰅, 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙, 𛰂𛱆 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛰅𛱁‌𛰚𛱁‌𛱞 𛱆𛰅‌𛰃𛱂 𛱆𛰂‌𛰜𛱛𛰃 𛰅𛱄‌𛰂𛱁 𛱂𛰄𛰋𛱇𛰅𛱁. 𛱞𛰀𛰃 𛰜𛰄𛱆𛰚𛰅𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙, 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛱊𛱁‌𛰅𛱁 𛱜‌𛱜; 𛰂𛱆 𛱇𛰆𛱇𛰂 𛰅𛱄‌𛰂𛱁 𛰜𛰄𛱆𛰚𛰅𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛱇𛰆𛱇‌𛰀𛱇, 𛰂𛱆 𛱇𛰆𛱄͏͏͏ 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰙𛱁𛰛 𛰃𛱄𛰙‌𛰃𛱄𛰙 𛱆𛰅‌𛰃𛱂 𛱁𛰚‌𛰅𛱁‌𛰃𛱇 𛰜𛰄𛱆𛰚𛰅𛰜 𛰙𛱁𛰛 𛰃𛱄𛰙‌𛰃𛱄𛰙. + +𛰅𛱄‌𛰂𛱁 𛱛𛰆𛰑𛱁𛰋 𛰃𛱚𛰚 𛱇𛰆𛱇𛰂 𛰂𛱛͏͏͏𛰜 𛰃𛱂‌𛱇𛱇 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰅𛱄‌𛰂𛱁 𛱛𛰆𛰑𛱁𛰋 𛰙𛱁‌𛰙𛱛𛰅 𛰆𛱄͏͏͏ 𛰂𛱛͏͏͏𛰜 𛱇𛰆𛱄͏͏͏ 𛰅𛰆𛱁𛰜𛰅‌𛰜𛰃𛱂 𛰙𛱁‌𛰙𛱛𛰅 𛰙𛱇𛰙‌𛰆𛱛𛰜 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜, 𛱆𛰀𛰃 𛱄𛰆‌𛰙𛱁𛰚 𛰂𛱆 𛱊𛱁‌𛰅𛱁 𛰅𛰆𛱛𛰣‌𛰙𛱇𛰚 𛱁‌𛱊𛱁𛰜 𛰃𛱇‌𛰅𛱆 𛱇𛰜‌𛰅𛱄𛰙 𛰂𛱆 𛰙𛱁‌𛰙𛱛𛰅 𛰙𛱇𛰙‌𛰆𛱛𛰜 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜. 𛱇𛰆𛱄͏͏͏ 𛰚𛱁𛱋‌𛰅𛱁 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛱆𛰅‌𛰃𛱂 𛰙𛱁‌𛰙𛱛𛰅 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛰅𛱁‌𛰅𛱜; 𛰅𛱄‌𛰂𛱆𛰃 𛰚𛱁𛱋‌𛰅𛱁 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛰂𛱛͏͏͏𛰜 𛱁‌𛱑 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛱇𛰆𛱄͏͏͏ 𛰃𛱇‌𛰅𛱆 𛱛‌𛰅𛱛𛰅 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛱜‌𛱜 𛰅𛱄‌𛰂𛱁 𛰂𛱛‌𛰆𛱂‌𛰅𛰆𛱇 𛰂𛱆 𛱆𛰂‌𛰜𛱛𛰃 𛰅𛱛‌𛰆𛱇 𛰅𛱄‌𛰂𛱁 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰊𛱁𛰋𛰈𛱇𛰚 𛰂𛱆 𛱇𛰆𛱇‌𛰀𛱇. 𛰅𛱁𛰆‌𛰃𛱁𛰛 𛰂𛱛͏͏͏𛰜 𛰅𛱁‌𛰅𛱜, 𛱛‌𛰅𛱛𛰅 𛰙𛱁𛰚 𛰂𛱆 𛰅𛰆𛱛𛰣‌𛰙𛱇𛰚 𛱁‌𛱊𛱁𛰜 𛰃𛱇‌𛰅𛱆 𛱇𛰜‌𛰅𛱄𛰙 𛰂𛱆 𛰙𛱁‌𛰙𛱛𛰅 𛰙𛱇𛰙‌𛰆𛱛𛰜 𛰅𛱁‌𛰚𛱁‌𛱞 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛱞𛰅 𛰜𛱁‌𛱊𛱁 𛰅𛱄‌𛰂𛱁 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛱂‌𛰚𛱁𛰜 𛰀𛱚𛰜. 𛰂𛱛‌𛰆𛱂‌𛰅𛰆𛱇 𛰈𛰋𛱇𛰃 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛱜‌𛱜 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰔𛱄‌𛰆𛱁𛰚 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰃𛱂‌𛰚𛱁𛰜 𛰀𛱚𛰜: 𛱇𛰆𛱄͏͏͏ 𛰅𛰆𛱁𛰅‌𛰜𛰃𛱂 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛰅𛱁‌𛰃𛱂 𛰂𛱛͏͏͏𛰜 𛱛‌𛰅𛱛𛰅 𛰙𛱁𛰚 𛰂𛱆 𛰅𛰆𛱛𛰣‌𛰙𛱇𛰚 𛰙𛱁‌𛰙𛱛𛰅 𛰙𛱇𛰙‌𛰆𛱛𛰜 𛱛‌𛰅𛱛𛰅 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜. 𛰂𛱆 𛱇𛰆𛱄͏͏͏ 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛱜‌𛱜 𛱆𛰅‌𛰃𛱂 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰙𛱁𛰚 𛰂𛱆 𛰅𛰆𛱛𛰣‌𛰙𛱇𛰚. 𛱞𛰅 𛰃𛰆𛱛𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰜𛱇𛱂‌𛰀𛱛𛰜 𛱛‌𛰅𛱛𛰅 𛰙𛱁𛰚 𛰂𛱆 𛰅𛰆𛱛𛰣‌𛰙𛱇𛰚 𛰂𛱆 𛰅𛱁‌𛰅𛱜 𛰂𛱛͏͏͏𛰜 𛱆𛰂‌𛰜𛱛𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛱂‌𛰚𛱁𛰜 𛰀𛱚𛰜 𛰅𛱆‌𛰅𛱛‌𛰆𛱇 𛰅𛱄‌𛰂𛱁 𛱁‌𛱊𛱁𛰜 𛰜𛰃𛱇𛰅 𛰅𛱄‌𛰂𛱁 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛱁𛰆‌𛰃𛱁𛰛 𛱇𛰆𛱇‌𛰀𛱇. 𛱇𛰆𛱄͏͏͏ 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰃𛱇‌𛰅𛱆 𛱛‌𛰅𛱛𛰅 𛰙𛱄𛰅𛰜𛰃 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙. 𛰂𛱆 𛱇𛰆𛱇𛰂 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛱜͏͏͏𛰛 𛰅𛰆𛱁𛰜‌𛰅𛱁. 𛱇𛰆𛱄͏͏͏ 𛱆𛰅‌𛰃𛱂 𛰜𛱁‌𛰆𛱇𛰅𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛱜‌𛱜 𛰅𛱄‌𛰂𛱁 𛰅𛰆𛱁𛰜‌𛰅𛱁. 𛰅𛱄‌𛰂𛱆𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛰆𛱛𛰜 𛰚𛱁‌𛰚𛱇𛰣 𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛰜𛱁‌𛱊𛱁 𛰅𛱄‌𛰂𛱁 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛱂‌𛰚𛱁𛰜 𛰀𛱚𛰜 𛰅𛱆‌𛰅𛱛‌𛰆𛱇 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰜𛰃𛱇𛰅. 𛰂𛱛͏͏͏𛰜 𛱆𛰀𛰃 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱂‌𛰃𛱜͏͏͏ 𛰅𛱄‌𛰂𛱁 𛱊𛱁‌𛱜 𛰂𛱆 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰔𛱄‌𛰆𛱁𛰚 𛱛‌𛰅𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛱜‌𛱜 𛰅𛱄‌𛰂𛱁 𛰀𛱚𛰜, 𛰅𛱄‌𛰂𛱆𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛱁‌𛱑 𛱜‌𛱜. 𛰂𛱆 𛰅𛱄‌𛰂𛱁 𛰅𛱁𛰆‌𛰃𛱁𛰛 𛱛‌𛰅𛱛𛰅. 𛰅𛱄‌𛰂𛱆𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛱜‌𛱜 𛰙𛱇𛰋𛰜𛱇 𛰂𛱛͏͏͏𛰜 𛱇𛰆𛱄͏͏͏ 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛱂‌𛰚𛱁𛰜 𛰅𛰆𛱂‌𛰃𛱜͏͏͏ 𛰅𛱄‌𛰂𛱁 𛱊𛱁‌𛱜 𛰂𛱆 𛰣𛱁‌𛰅𛱄 𛱇𛰆𛱄͏͏͏. 𛱇𛰆𛱄͏͏͏ 𛱁‌𛱑 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜. 𛱇𛰆𛱄͏͏͏ 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛰅𛱄‌𛰂𛱁 𛰅𛱁𛰀 𛰣𛱁‌𛰅𛱄 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜. + +𛱆𛰀𛰃 𛰜𛱄𛰚 𛱁‌𛱑 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰔𛱄 𛰅𛱄‌𛰂𛱁 𛱛𛰆𛰑𛱁𛰋 𛰃𛱚𛰚 𛱊𛱁‌𛰅𛱁 𛰜𛰃𛱄𛰚 𛱄𛱇‌𛰀𛱁𛰃. 𛱇𛰆𛱄͏͏͏ 𛰅𛱁‌𛰅𛱜 𛱛‌𛰅𛱛𛰅 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰅𛱜‌𛰚𛱇‌𛰜𛱇𛰙 𛰚𛱁‌𛰚𛱇𛰣 𛰅𛱄‌𛰂𛱁 𛱄𛱇‌𛰀𛱁𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁. 𛰅𛱄‌𛰂𛱁 𛰙𛱁‌𛰅𛱛𛰅 𛰀𛱚𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱂‌𛰙𛱁‌𛰚𛱜͏͏𛰜: 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛱜‌𛱜 𛱆𛰅‌𛰃𛱂 𛱁𛰆‌𛰅𛱆 𛰣𛱁‌𛰅𛱄 𛰂𛱆 𛰙𛱁‌𛰅𛱛𛰅 𛰃𛰆𛱛𛰜 𛰅𛱁‌𛰙𛱄‌𛰜𛱁𛰅. 𛱇𛰆𛱄͏͏͏ 𛰅𛰆𛱁𛰅‌𛰜𛰃𛱂 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛱆𛰅‌𛰃𛱂 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛱇𛰆𛱇‌𛰀𛱇. 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰜𛰅𛱛‌𛰅𛱛𛰙 𛰃𛱄𛰙‌𛰃𛱄𛰙 𛰅𛱄‌𛰂𛱁 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰜𛰃𛱒‌𛱇𛰆 𛱛‌𛰅𛱛𛰅 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙, 𛰂𛱆 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛰂𛱆𛰚𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰥𛱇𛰅‌𛰥𛱇𛰅 𛰅𛱄‌𛰂𛱁 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰂𛱆 𛰙𛱛𛰜‌𛰙𛱛𛰜 𛰆𛱂‌𛰃𛱇𛰃, 𛰅𛱁𛰆𛱂‌𛰅𛱁𛰆𛱂, 𛰙𛱁𛰚 𛰆𛱂‌𛰙𛱛‌𛰃𛱄͏͏͏, 𛰂𛱆 𛰆𛱁𛱆𛰚𛰜. 𛰃𛱂‌𛱇𛱇 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰆𛱄͏͏͏‌𛰆𛱄͏͏͏ 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰜𛱇𛱂‌𛰂𛱛𛰃𛰆 𛰅𛱄‌𛰂𛱁 𛰙𛱄𛰅𛰜𛰃 𛰀𛱄𛰋𛰚 𛰂𛱆 𛱆𛰀𛰃 𛰅𛱄‌𛱑‌𛰅𛱄‌𛱑 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛰅𛱁‌𛰚𛱁‌𛰙𛱄𛰅𛰜𛰃 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰀𛱄𛰋𛰚. + +𛰅𛱁‌𛰚𛱁‌𛰙𛱄𛰅𛰜𛰃 𛱛‌𛰅𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛱆𛰀𛰃 𛰃𛱂‌𛰚𛱁𛰜 𛰙𛱁𛰚; 𛱇𛰆𛱄͏͏͏ 𛱊𛱁‌𛰅𛱁 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛰙𛱁‌𛰙𛱁 𛰂𛱆 𛰂𛱁‌𛰂𛱁, 𛰅𛱄‌𛰂𛱆𛰃 𛱆𛰀𛰃 𛰃𛱂‌𛰚𛱁𛰜 𛰃𛰆𛱇𛰆 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛱊𛱁‌𛰅𛱁 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃. 𛰂𛱆 𛱊𛱁‌𛰅𛱁 𛱁‌𛱊𛱁𛰜 𛰃𛱇‌𛰅𛱆 𛱛‌𛰅𛱛𛰅 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜. 𛱁‌𛱊𛱁𛰜 𛰜𛱇𛰅 𛰙𛱁‌𛰙𛱛𛰅 𛰙𛱇𛰙‌𛰆𛱛𛰜 𛱊𛱁‌𛰅𛱁 𛰙𛱁‌𛰙𛱁 𛰂𛱆 𛰂𛱁‌𛰂𛱁, 𛰂𛱆 𛰅𛱄‌𛰂𛱆𛰃 𛱛‌𛰅𛱛𛰅 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰙𛱁‌𛰙𛱛𛰅 𛰃𛰆𛱛𛰜 𛱊𛱁‌𛰅𛱁 𛰃𛱄𛰙‌𛰃𛱄𛰙 𛱁𛰆‌𛰃𛱂. 𛰅𛱁‌𛰚𛱁‌𛱞 𛰃𛱂‌𛰚𛱁𛰜 𛱁‌𛱊𛱁𛰜 𛰃𛱇‌𛰅𛱆 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰂𛱆 𛰃𛱇‌𛰅𛱆 𛰚𛱁‌𛰚𛱇𛰣 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰂𛰆𛱇. 𛰅𛱁‌𛰅𛱜, 𛱇𛰆𛱄͏͏͏ 𛱁‌𛱑 𛱊𛱁‌𛰅𛱁 𛰅𛰋𛱁𛱆. 𛱛‌𛰅𛱛𛰅 𛰃𛱂‌𛰚𛱁𛰜 𛰙𛱁𛰚 𛱊𛱁‌𛰅𛱁 𛰚𛱇𛰙 𛰙𛱇𛰚𛱇𛰜 𛰃𛰆𛱛𛰜 𛰃𛱄𛰙‌𛰃𛱄𛰙 𛰂𛱛͏͏͏𛰜 𛱊𛱁‌𛰅𛱁 𛰂𛰆𛱇 𛰅𛱄‌𛰂𛱁 𛱊𛱁‌𛰅𛱁 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛱞𛰅 𛰜𛱁‌𛱊𛱁 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰥𛱇𛰅‌𛰥𛱇𛰅. + +𛰣𛱁‌𛰅𛱄 𛰃𛰆𛱛𛰚 𛰃𛱂‌𛰚𛱁𛰜 𛰜𛱄𛰚 𛰅𛱁𛰀 𛱛‌𛰅𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛱛𛰆𛰑𛱁𛰋 𛰃𛱚𛰚, 𛰂𛱆 𛱞𛰅 𛰅𛱁‌𛰃𛱂 𛰙𛱇𛰚𛱇𛰜 𛰃𛰆𛱁𛰂 𛱊𛱁‌𛰅𛱁 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜. 𛰂𛱛͏͏͏𛰜 𛱊𛱁‌𛰅𛱁 𛰅𛰋𛱁𛱆 𛰅𛱄‌𛰂𛱁 𛰙𛱁‌𛰅𛱛𛰅 𛰀𛱚𛰜, 𛰅𛱁𛰚‌𛰜𛱇𛰀 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰙𛱁‌𛰙𛱛𛰅 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛰅𛱄‌𛰂𛱁 𛱊𛱁‌𛰅𛱁 𛰅𛱁‌𛰃𛱂 𛱛‌𛰅𛱛𛰅 𛱄𛰆‌𛰙𛱁𛰚 𛰂𛱆 𛱊𛱁‌𛰅𛱁 𛰅𛰆𛱛𛰣‌𛰙𛱇𛰚, 𛰂𛱆 𛱞𛰀𛰃 𛰅𛱁‌𛰃𛱂 𛱛‌𛰅𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛱜‌𛱜 𛰅𛱄‌𛰂𛱁 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰀𛱚𛰜 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰔𛱄‌𛰆𛱁𛰚 𛱛‌𛰅𛱛𛰅 𛰂𛱛‌𛰆𛱂‌𛰅𛰆𛱇. 𛰂𛱛͏͏͏𛰜 𛰙𛱇𛰚𛱇𛰜 𛰔𛱄‌𛰆𛱁𛰚 𛱛‌𛰅𛱛𛰅 𛰜𛱇𛱇‌𛰜𛱇𛰙, 𛱊𛱁‌𛰅𛱁 𛰅𛱄‌𛰂𛱆𛰃 𛰅𛰋𛱁𛱆. 𛰣𛱇 𛱊𛱁‌𛰅𛱁 𛰜𛰃𛱒‌𛱇𛰆. 𛱊𛱁‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛰜𛱁‌𛰀𛱁‌𛰆𛱇 𛱊𛱁‌𛰅𛱁 𛰆𛱇‌𛰙𛱁 𛰅𛱄‌𛰂𛱁 𛰜𛰅𛱂𛱆 𛰂𛱆 𛱜‌𛱜 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰆𛱂‌𛰆𛱁𛰚𛰊 𛰜𛰃𛱒‌𛱇𛰆: 𛱇𛰆𛱄͏͏͏ 𛱛‌𛰅𛱛𛰅 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛱆𛰅‌𛰃𛱂 𛱊𛱁‌𛰅𛱁 𛱜‌𛱜. 𛰂𛱆 𛱇𛰆𛱄͏͏͏ 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛱇‌𛰅𛱆 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜. 𛰅𛱄‌𛰂𛱆𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰚𛱁‌𛰚𛱇𛰣 𛰜𛱁‌𛰀𛱁‌𛰆𛱇: 𛱛‌𛰅𛱛𛰅 𛰜𛰅𛱂𛱆 𛰂𛱆 𛰅𛰆𛱚𛰈𛰜 𛰣𛱁‌𛰅𛱄 𛰀𛰆𛱄𛱆‌𛰙𛱁. 𛱁‌𛱊𛱁𛰜 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛱛‌𛰅𛱛𛰅. 𛰂𛱛͏͏͏𛰜 𛱛‌𛰅𛱛𛰅 𛰃𛱂‌𛰚𛱁𛰜 𛰙𛱁𛰚 𛰜𛰃𛱒‌𛱇𛰆, 𛱛‌𛰅𛱛𛰅 𛰅𛰆𛱚𛰈𛰜 𛰣𛱁‌𛰅𛱄 𛰅𛱁‌𛰅𛱜 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰙𛱁‌𛱞𛰣: 𛰅𛱁‌𛰅𛱜 𛱁‌𛱑 𛰙𛱁‌𛱞𛰣 𛰣𛱁‌𛰅𛱄 𛰙𛱇𛰅𛰜𛰃 𛰅𛱁‌𛰚𛱁‌𛰙𛱄𛰅𛰜𛰃. 𛰂𛱆 𛰅𛱜‌𛰚𛱇‌𛰜𛱇𛰙 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰚𛱁‌𛰚𛱇𛰣 𛱆𛰅‌𛰃𛱂 𛰅𛱁‌𛰅𛱜 𛰂𛱛͏͏͏𛰜 𛰃𛱛͏͏͏‌𛰙𛱁𛰣 𛰚𛱁‌𛱞‌𛰃𛰅𛱁 𛰃𛱄𛰙‌𛰃𛱄𛰙 𛰅𛰆𛱁𛰜‌𛰅𛱁… + +𛱛‌𛰅𛱛𛰅 𛰂𛱛‌𛰆𛱂‌𛰅𛰆𛱇 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰙𛱁𛰛 𛱛𛰆𛰑𛱁𛰋 𛰃𛱚𛰚 𛰂𛱆 𛱞𛰅 𛰅𛱁𛰚‌𛰜𛱇𛰀 𛱞𛰀𛰃 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰚𛱁‌𛰚𛱇𛰣 𛰅𛰆𛱁𛰜‌𛰅𛱁. 𛰂𛱆 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰣𛱁‌𛰅𛱄 𛰅𛱜͏͏͏𛰛: 𛱇𛰆𛱄͏͏͏ 𛱆𛰀𛰃 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰚𛱁‌𛰚𛱇𛰣 𛰅𛱄‌𛰂𛱁 𛰃𛱚𛰚. 𛰅𛱄‌𛰂𛱁 𛰅𛱁‌𛰚𛱁‌𛱞 𛰀𛱚𛰜 𛱛‌𛰅𛱛𛰅 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰣𛱁‌𛰅𛱄 𛱇𛰆𛱄͏͏͏: 𛱁‌𛱊𛱁𛰜 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰂𛱆 𛰃𛱂‌𛰚𛱁𛰜, 𛰃𛰆𛱇𛰆, 𛰆𛱇‌𛰊𛰆𛱇, 𛰆𛱇‌𛰅𛰋𛱇𛰙, 𛰃𛰆𛱇𛰆. 𛱄𛰆‌𛰙𛱁𛰚 𛰅𛰋𛱁𛰚𛱄𛰚, 𛰃𛱂‌𛱇𛱇 𛰅𛱄‌𛰂𛱁 𛰃𛱚𛰚, 𛱊𛱁‌𛰅𛱁 𛱜‌𛱜 𛰂𛱛͏͏͏𛰜 𛱛‌𛰅𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰅𛱁𛰂‌𛰛𛱜‌𛰆𛱂 𛱛‌𛰅𛱛𛰅 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜. 𛰅𛰆𛱛͏͏͏‌𛰚𛱁𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛱇‌𛰅𛱆 𛰂𛱁‌𛰃𛰆𛱁𛰣 𛰆𛱂‌𛰂𛱆‌𛰆𛱇‌𛰃𛱁𛰜 𛰅𛱄‌𛰂𛱁 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙. 𛱊𛱁‌𛰅𛱁 𛰙𛱁‌𛰜𛱁‌𛰣𛱇 𛱜‌𛱜 𛱛‌𛰅𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰂𛱆 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰥𛱇𛰅‌𛰥𛱇𛰅. 𛰂𛱆 𛱆𛰀𛰃 𛰙𛱁𛰚, 𛱊𛱁‌𛰅𛱁 𛰚𛱇𛰙 𛰚𛱇𛰑 𛰂𛱆 𛱊𛱁‌𛰅𛱁 𛰃𛰆𛱛𛰜 𛰚𛱁‌𛰚𛱇𛰣 𛰂𛱆‌𛰂𛱁, 𛱊𛱁‌𛰅𛱁 𛱜‌𛱜 “𛰃𛰆𛱛𛰜 𛱛‌𛰅𛱛𛰅 𛰙𛱁‌𛰜𛱁‌𛰣𛱇 𛰙𛱁𛰚 𛰂𛱆 𛰅𛰆𛱛𛰣‌𛰙𛱇𛰚 𛰃𛰆𛱁𛰂 𛱛‌𛰅𛱛𛰅 𛰆𛱂‌𛰂𛱆‌𛰆𛱇‌𛰃𛱁𛰜”. 𛰂𛱆 𛰚𛱁‌𛱞‌𛰃𛰅𛱁 𛱛‌𛰅𛱛𛰅 𛰙𛱁𛰚 𛰂𛱆 𛰅𛰆𛱛𛰣‌𛰙𛱇𛰚 𛰅𛱜‌𛰚𛱇‌𛰜𛱇𛰙 𛰙𛱁‌𛰙𛱛𛰅 𛰙𛱇𛰙‌𛰆𛱛𛰜 𛱇𛰆𛱇𛰂 𛱁‌𛱑 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜. 𛰂𛱆 𛱇𛰆𛱄͏͏͏ 𛰅𛰆𛱁𛰅‌𛰜𛰃𛱂 𛰃𛱇‌𛰅𛱆 𛰙𛱁‌𛰙𛱛𛰅 𛰅𛱄𛰋𛰃 𛰀𛱚𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁. 𛱞𛰀𛰃 𛰇𛱁𛰋𛰅𛱆𛰂 𛱊𛱁‌𛰅𛱁 𛰃𛱂‌𛰚𛱁𛰜 𛰙𛱁𛰚 𛱁𛰃𛱁𛰆 𛱜‌𛱜 𛰂𛱛͏͏͏𛰜 𛰆𛱁𛰜𛰃 𛰂𛱛‌𛰆𛱂‌𛰅𛰆𛱇 𛱊𛱁‌𛰅𛱁 𛰚𛱁‌𛰚𛱇𛰣 𛰅𛱁‌𛰚𛱁‌𛱞 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛰅𛰆𛱂‌𛰀𛱁‌𛰚𛱇 𛰅𛱄‌𛰂𛱁 𛰙𛱁‌𛰜𛱁‌𛰣𛱇 𛰙𛱁𛰚 𛱊𛱁‌𛰅𛱁 𛰀𛱚𛰜, 𛰅𛱆‌𛰅𛱛‌𛰆𛱇 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰜𛰃𛱇𛰅. 𛰃𛰆𛱂‌𛱜 𛱛‌𛰅𛱛𛰅 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱂‌𛰃𛱜͏͏͏ 𛰋𛱚𛰚 𛱛‌𛰅𛱛𛰅 𛰀𛱚𛰜. 𛰙𛱄𛰅𛰜𛰃 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰅𛱆𛰙‌𛰃𛱂 𛰅𛱄‌𛰂𛱁 𛰙𛱄𛰅𛰜𛰃 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜, 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛰆𛱂‌𛰃𛱜͏͏͏ 𛰋𛱚𛰚. 𛰅𛱁‌𛰅𛱜 𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰙𛱁‌𛱞𛰣 𛰃𛱂‌𛰙𛱁‌𛰚𛱜͏͏𛰜. 𛱇𛰆𛱄͏͏͏ 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛰚𛱁‌𛱞‌𛰃𛰅𛱁 𛱛‌𛰅𛱛𛰅 𛰃𛱂‌𛰚𛱁𛰜 𛰙𛱁𛰚. 𛰈𛰋𛱇𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛱜͏͏͏𛰛 𛱛‌𛰅𛱛𛰅 𛱄𛰆‌𛰙𛱁𛰚 𛰂𛱆 𛰅𛱄‌𛰂𛱆𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛱇‌𛰅𛱆 𛰙𛱁‌𛰙𛱛𛰅 𛰅𛱄𛰋𛰃 𛰀𛱚𛰜 𛱊𛱁‌𛰅𛱁 𛰂𛱛͏͏͏𛰜 𛱊𛱁‌𛰅𛱁 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛰅𛰆𛱂‌𛰀𛱁‌𛰚𛱇 𛰅𛱄‌𛰂𛱁 𛱊𛱁‌𛰅𛱁 𛰀𛱚𛰜 𛰂𛱆 𛰜𛱁‌𛱊𛱁 𛰅𛱄‌𛰂𛱁 𛱊𛱁‌𛰅𛱁 𛰅𛱁𛰆‌𛰃𛱁𛰛 𛱇𛰆𛱇‌𛰀𛱇. + +𛰅𛱁‌𛰅𛱜, 𛰅𛱁𛰆‌𛰃𛱁𛰛 𛱛‌𛰅𛱛𛰅 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰣𛱁‌𛰅𛱄 𛰜𛱁‌𛰆𛱇𛰅𛰜, 𛰂𛱆 𛰅𛰆𛱂‌𛰃𛱜͏͏͏ 𛰜𛰆𛱇𛰂. 𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰊𛱆𛰃‌𛱄͏͏͏𛰂 𛰃𛱂‌𛰚𛱁𛰜 𛰜𛱄𛰚: 𛰀𛱜! 𛱞𛰀𛰃 𛰅𛱁‌𛰚𛱁‌𛱞 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛰅𛱄‌𛰂𛱁 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰀𛱚𛰜! 𛱁‌𛱊𛱁𛰜 𛰂𛱆 𛰃𛱂‌𛰚𛱁𛰜, 𛰃𛰆𛱇𛰆, 𛰆𛱇‌𛰊𛰆𛱇, 𛰆𛱇‌𛰅𛰋𛱇𛰙, 𛰂𛱆 𛰃𛰅𛱄𛰂. 𛱇𛰆𛱄͏͏͏ 𛱆𛰀𛰃 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰣𛱁‌𛰅𛱄 𛱇𛰆𛱄͏͏͏. 𛰂𛱆 𛱁‌𛱊𛱁𛰜 𛰊𛰋𛱇𛰜 𛱛‌𛰅𛱛𛰅 𛰂𛱛‌𛰂𛱛͏͏͏𛰜, 𛰂𛱆 𛱁‌𛱊𛱁𛰜 𛰃𛰆𛱛𛰜 𛰃𛱄𛰙‌𛰃𛱄𛰙 𛰅𛰆𛱁𛰜‌𛰅𛱁. 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛱁‌𛱑 𛱜‌𛱜 𛰅𛱁‌𛰚𛱁‌𛰙𛱄𛰅𛰜𛰃 𛰅𛱁‌𛰃𛱂 𛱛‌𛰅𛱛𛰅, 𛰂𛱆 𛰃𛰆𛱁𛰂 𛰜𛰅𛱛‌𛰅𛱛𛰙 𛰃𛱄𛰙‌𛰃𛱄𛰙. 𛱄𛰆‌𛰙𛱁𛰚 𛰅𛰋𛱁𛰚𛱄𛰚 𛱞𛰀𛰃 𛱊𛱁‌𛰅𛱁 𛱜‌𛱜 𛰂𛱛͏͏͏𛰜 𛱛‌𛰅𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰅𛱁𛰂‌𛰛𛱜‌𛰆𛱂 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜. 𛱞𛰅 𛰅𛱁𛰚‌𛰜𛱇𛰀 𛱁𛰚‌𛰅𛱁‌𛰃𛱇 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰅𛱆‌𛰆𛱂‌𛰂𛱂𛱆 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰙𛱁‌𛰜𛱁‌𛰣𛱇 𛰙𛱁𛰚 𛱊𛱁‌𛰅𛱁 𛰀𛱚𛰜. 𛰂𛱆 𛰅𛱁‌𛰚𛱁‌𛱞 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛱆𛰀𛰃 𛰃𛱄𛰙‌𛰃𛱄𛰙 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅: 𛱇𛰆𛱄͏͏͏ 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰃𛱇‌𛰅𛱆 𛰙𛱁𛰅‌𛰙𛱁𛰅 𛱛‌𛰅𛱛𛰅 𛰃𛱂‌𛰚𛱁𛰜 𛰜𛱄𛰚, 𛰂𛱆 𛱁‌𛱊𛱁𛰜 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛱛‌𛰅𛱛𛰅. 𛰙𛱄𛰅𛰜𛰃 𛰜𛱄𛰚 𛱛‌𛰅𛱛𛰅 𛰊𛰋𛱇𛰜 𛰂𛱆 𛰆𛱇‌𛰜𛱇 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛱇𛰆𛱄͏͏͏ 𛰃𛱇‌𛰅𛱆 𛰙𛱁𛰅‌𛰙𛱁𛰅: 𛰅𛱄‌𛰂𛱆𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛱁𛰆‌𛰃𛱁𛰛 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛱞𛰅 𛰜𛱁‌𛱊𛱁 𛰅𛱄‌𛰂𛱁 𛰂𛱁‌𛱊𛱁 𛰂𛱆 𛰅𛱄‌𛰂𛱁 𛰜𛱄𛰚. + +𛰅𛱄‌𛰂𛱆𛰃 𛰅𛱁‌𛰚𛱁‌𛱞 𛱆𛰀𛰃 𛰜𛱄𛰚‌𛰈𛱇 𛰂𛱆 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰚𛱁‌𛰚𛱇𛰣 𛱇𛰆𛱄͏͏͏ 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛰆𛱂𛱆𛰃 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰙𛱁‌𛰜𛱁‌𛰣𛱇 𛰙𛱁𛰚 𛱊𛱁‌𛰅𛱁 𛰀𛱚𛰜 𛰅𛱆‌𛰅𛱛‌𛰆𛱇 𛰅𛱄‌𛰂𛱁 𛰜𛰃𛱇𛰅. 𛰃𛱂‌𛰚𛱁𛰜 𛰚𛱇𛰑 𛱜‌𛱜 𛰂𛱛͏͏͏𛰜, 𛰅𛱄‌𛰂𛱆𛰃 𛱛‌𛰅𛱛𛰅 𛰂𛱛‌𛰆𛱂‌𛰅𛰆𛱇 𛰅𛱁𛰀 𛰣𛱁‌𛰅𛱄 𛱇𛰆𛱄͏͏͏ 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜, 𛱇𛰆𛱄͏͏͏ 𛰅𛰆𛱁𛰅‌𛰜𛰃𛱂 𛰚𛱁‌𛰚𛱇𛰣 𛱛‌𛰅𛱛𛰅 𛱄𛰆‌𛰙𛱁𛰚 𛰂𛱆 𛱊𛱁‌𛰅𛱁 𛰅𛰆𛱛𛰣‌𛰙𛱇𛰚. 𛰅𛱄‌𛰂𛱆𛰃 𛱆𛰀𛰃 𛱞𛰀𛰃 𛰜𛱄𛰚‌𛰈𛱇 𛰂𛱆 𛰃𛱂‌𛱇𛱇 𛰅𛱄‌𛰂𛱁 𛰃𛱚𛰚 𛰙𛱁‌𛰙𛱛𛰅 𛰃𛱄𛰙‌𛰃𛱄𛰙 𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱂‌𛰃𛱜͏͏͏ 𛱜‌𛱜 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰙𛱄𛰅𛰜𛰃 𛰙𛱁‌𛰜𛱁‌𛰣𛱇 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙. 𛱊𛱁‌𛰅𛱁 𛰅𛰆𛱂‌𛰃𛱜͏͏͏ 𛰅𛱁‌𛰚𛱁‌𛰙𛱄𛰅𛰜𛰃 𛰛𛱁𛰚𛰊 𛰂𛱆 𛰑𛱛𛰆 𛰂𛱛͏͏͏𛰜 𛱞𛰀𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰚𛱁‌𛰚𛱇𛰣. 𛰛𛱁𛰚𛰊 𛰙𛱁‌𛰙𛱛𛰅 𛰣𛱇𛰅‌𛰙𛱇𛰚 𛱆𛰅‌𛰃𛱁𛰜 𛰂𛱆 𛰑𛱛𛰆 𛱊𛱁‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛰅𛱑𛰃 𛰜𛰃𛱄𛰚. 𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛰀𛱁‌𛰆𛱁𛰅 𛱛‌𛰅𛱛𛰅 𛰀𛱚𛰜 𛱊𛱁‌𛰅𛱁 𛰆𛱂‌𛰂𛱄𛰋𛰃, 𛰅𛱄‌𛰂𛱆𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰚𛱁‌𛰚𛱇𛰣 𛱛‌𛰅𛱛𛰅: 𛰙𛱄𛰅𛰜𛰃 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰇𛱄𛰚 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛰅𛱄‌𛰂𛱁 𛱇𛰆𛱇‌𛰀𛱇, 𛰂𛱆 𛰅𛱄‌𛰂𛱁 𛰂𛱛‌𛰆𛱂‌𛰅𛰆𛱇 𛰃𛱂‌𛰚𛱁𛰜 𛱁‌𛱑 𛰇𛱆‌𛰃𛱇𛰆 𛰅𛱛‌𛰆𛱇 𛰋𛱚𛰚. + +𛱊𛱁‌𛱜 𛰃𛱂‌𛱇𛱇 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰅𛱄‌𛰂𛱁 𛱛𛰆𛰑𛱁𛰋 𛰃𛱚𛰚 𛱁‌𛱑 𛱜‌𛱜 𛰅𛱁‌𛰚𛱁‌𛰙𛱄𛰅𛰜𛰃. 𛰜𛱁𛰑, 𛱛‌𛰅𛱛𛰅 𛰙𛱁𛰚 𛱊𛱁‌𛰅𛱁 𛰃𛰆𛱛𛰜 𛰚𛱁‌𛰚𛱇𛰣 𛰙𛱇𛰙‌𛰆𛱛𛰜 𛰃𛱇‌𛰆𛱇‌𛰅𛱛𛰙, 𛱁‌𛱑 𛱜‌𛱜 𛰅𛱁‌𛰚𛱁‌𛰙𛱄𛰅𛰜𛰃 𛰚𛱇𛰑, 𛱛‌𛰅𛱛𛰅 𛰙𛱁𛰚 𛱊𛱁‌𛰅𛱁 𛰃𛰆𛱛𛰜 𛰚𛱁‌𛰚𛱇𛰣 𛰂𛱆‌𛰂𛱁; 𛰅𛱁‌𛰚𛱁‌𛱞 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛱁‌𛱑 𛱁𛰜𛰅 𛱄𛰆‌𛰙𛱁𛰚 𛰅𛰋𛱁𛰚𛱄𛰚 𛰂𛱆 𛰛𛱁𛰚𛰊 𛰂𛱆 𛰑𛱛𛰆. 𛱞𛰀𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛱁‌𛱑 𛱁𛰜𛰅 𛰃𛱂‌𛰚𛱁𛰜 𛱁𛰃𛱁𛰆, 𛰇𛱁𛰋𛰅𛱆𛰂 𛱊𛱁‌𛰅𛱁 𛰃𛱂‌𛰚𛱁𛰜 𛰙𛱁𛰚, 𛰂𛱆 𛰂𛱁‌𛰃𛰆𛱁𛰣 𛰅𛱁𛰚‌𛰈𛱇 𛰅𛱄‌𛰂𛱁 𛱊𛱁‌𛰅𛱁. 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛱁‌𛱑 𛱜‌𛱜 𛰅𛱁‌𛰃𛱂 𛱛‌𛰅𛱛𛰅 𛰙𛱁‌𛰜𛱁‌𛰣𛱇 𛱄𛰆‌𛰙𛱁𛰚 𛰂𛱆 𛱊𛱁‌𛰅𛱁 𛰅𛰆𛱛𛰣‌𛰙𛱇𛰚, 𛰅𛱁‌𛰃𛱂 𛱛‌𛰅𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙, 𛰅𛱁‌𛰃𛱂 𛱛‌𛰅𛱛𛰅 𛰃𛱂‌𛰚𛱁𛰜 𛰙𛱇𛰚𛱇𛰜 𛰂𛱆 𛱊𛱁‌𛰅𛱁 𛰃𛰆𛱇𛰆 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜, 𛰅𛱁‌𛰃𛱂 𛰙𛱇𛰚𛱇𛰜 𛱊𛱁‌𛰅𛱁 𛰜𛰃𛱒‌𛱇𛰆, 𛰅𛱁‌𛰃𛱂 𛰜𛰅𛱂𛱆 𛰂𛱛͏͏͏𛰜 𛱊𛱁‌𛰅𛱁 𛰜𛰃𛱒‌𛱇𛰆, 𛱆𛰅‌𛰃𛱂 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰙𛱁‌𛰙𛱛𛰅 𛱛‌𛰅𛱛𛰅 𛰂𛱛‌𛰆𛱂‌𛰅𛰆𛱇 𛰅𛱁𛰀 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰙𛱁𛰛 𛱛𛰆𛰑𛱁𛰋 𛰃𛱚𛰚, 𛰂𛱆 𛱆𛰅‌𛰃𛱂 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛰆𛱁𛰂 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰃𛱂‌𛰚𛱁𛰜 𛰀𛱚𛰜 𛰅𛱆‌𛰅𛱛‌𛰆𛱇 𛰅𛱄‌𛰂𛱁 𛰜𛰃𛱇𛰅 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰅𛱁𛰆‌𛰃𛱁𛰛 𛱇𛰆𛱇‌𛰀𛱇. + +𛰅𛱄‌𛰂𛱆𛰃 𛱛‌𛰅𛱛𛰅, 𛰃𛱂‌𛱇𛱇 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰙𛱁‌𛰙𛱛𛰅 𛱁‌𛱊𛱁𛰜 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰆𛱄͏͏͏: 𛰅𛱁‌𛰚𛱁‌𛱞 𛰅𛱄‌𛰂𛱁 𛰀𛱁𛰑𛱇𛰊 𛰙𛱁‌𛰅𛱛𛰅 𛰀𛱚𛰜 𛰂𛱆 𛱛‌𛰅𛱛𛰅 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛱛‌𛰆𛱇 𛰅𛱄‌𛰂𛱁 𛰚𛱇𛰋 𛱇𛰆𛱇‌𛰀𛱇 𛰅𛱜‌𛰚𛱇‌𛰜𛱇𛰙 𛱁‌𛱑 𛱜‌𛱜 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰆𛱄͏͏͏. 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛱛‌𛰅𛱛𛰅 𛰆𛱄͏͏͏: 𛱞𛰅 𛰃𛰆𛱛𛰜 𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱁𛰅‌𛰜𛰃𛱂 𛰙𛱁‌𛰙𛱛𛰅 𛰙𛱇𛰙‌𛰆𛱛𛰜 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜. + +𛰅𛱄‌𛰂𛱆𛰃 𛰅𛱁‌𛰅𛱜 𛱛‌𛰅𛱛𛰅 𛰜𛱇𛱇‌𛰜𛱇𛰙 diff --git a/libs/harfbuzz/perf/texts/fa-words.txt b/libs/harfbuzz/perf/texts/fa-words.txt new file mode 100644 index 000000000..4937544d8 --- /dev/null +++ b/libs/harfbuzz/perf/texts/fa-words.txt @@ -0,0 +1,10000 @@ +و +در +به +از +ویکی‌پدیا +که +را +این +با +است +رده +برای +کاربر +، +بحث +تصویر +میلادی +ایران +تاریخ +نام +پرونده +آن +یک +ساعت +صفحهٔ +کنید +پیوند +مقاله +صفحه +شما +اصلی +عنوان +یا +تا +سال +هم +من +استفاده +بر +خود +شده +شد +تغییرمسیر +شهرستان +کار +راهنمای +اگر +تکثیر +چه +ویرایش +حق +مقاله‌های +می +فارسی +نیست +دیگر +نوشتن +پنج +بود +زبان +سیارک +امضا +کمک +شیوه‌نامه +منابع +ملی +ثبت +آثار +پانویس +۱۱ +میز +خودآموز +بخش +دارد +خرد +انگلیسی +او +لطفاً +نیز +۱۵ +شماره +پهنا +بنیاد +استان +هر +اثر +می‌شود +مورد +کرد +یادکرد +امیدوارم +راهنما +کنیم +خوش +۱ +ویکی +چیزی +پس +۰ +۲ +شهر +پیش +فهرست +مرجع +خط +آمدید +اطلاعات +اینجا +تاریخی +زیر +منبع +جعبه +جدید +دوره +بیشتر +اینکه +بهتر +یکی +شود +دو +سپتامبر +راهنمایی +پیوندهای +۵ +حذف +۲۰۰۰ +خوب +۳ +نظر +آزاد +قرار +خواهد +تمرین +باشد +بله +پیرامون +سلام +آموزش +۴ +اصل +۱۰ +نه +صفحات +۱۹ +۱۲ +۲۰۱۱، +های +پاس +ولی +توسط +چگونه +برگزیده +بداریم +فقط +ویکی‌پروژه +۲۰۰۱ +روی +سریع +اکتبر +صورت +دست +قهوه‌خانه +۱۴ +دانشگاه +بنیادی +اما +بیاید +ناشر +داشتید، +باید +بروید +الگو +چهار +اول +مارس +کتاب +ایجاد +بازدید +توجه +آنها +پایه +۲۰ +کشور +ساختار +سخ +خوش‌آمدید +مقالهٔ +شده‌است +سازمان +فارسی‌نویسی +بودن +مرکزی +باز +آمریکا +وب +ب +۱۶ +نویسنده +کادر +دسامبر +صورتی +۲۰۰۷ +۱۸ +۲۰۱۰، +کند +فنی +تصمیم +۱۳ +تهران +وجود +۱۷ +نشانی +چطور +چند +کشف +اوت +دانشنامه‌ای +فوتبال +علمی +۲۰۰۸، +درج +۲۰۰۲ +هستند +بگیرید +۲۱ +۲۰۱۱ +نوامبر +مطالب +آزمایش +وی +کاربران +فیلم +ها +ماندن +مقالات +بپرسید +حروف +لذت +جمعیت +بحثم +۶ +ببرید +خوشتان +۸ +مدک +وابسته +ویکی‌پدیانویس +ویکی‌پدیانویسان +۷ +۲۰۰۹، +اسلام +۲۲ +ی +مسایل +آوریل +بنویسیم +۱۹۹۹ +کاربری +علامت +واقع +شوید +اهمیت +۲۳ +کلاس +کردن +ای +آشنا +باشید +نگاهی +کوچک +نکنید +وب‌گاه +پروژه‌های +کرده +۲۸ +می‌توانید +انتخاب +۹ +مکنید +بعد +روز +است، +جستارهای +شدن +نوع +نمونه‌های +۲۴ +نفر +دارید، +بیندازید +خودکار +۲۰۰۶ +نوشته +مطالعهٔ +انبار +عجله +غفلت +فهرست‌شده +مشارکت +اهل +۲۵ +سوال +محمد +بوده +۳۰ +بسیار +بزرگ +میراث +میان +زمان +منابعی +اثبات‌پذیری +جلالی +سیارک‌های +دهستان +مرکز +انجام +فوریه +می‌کند +۲۶ +نام‌های +ما +یعنی +ایرانی +ژوئن +غیر +پایان +یونسکو +حال +پرحجم +چپ +می‌گویم +داشته +جمله +پیام +عمومی +گردشگری +قبل +همین +همچنین +همان +مالک +سپاسگزارم +سال‌های +همه +اندازه +مربوط +ویکی‌انبار +قدر +چون +بیرون +ویکی‌نویسی +داده +کسب +دوم +ویژه +هیچ +فرهنگ +کسی +بروید، +تنها +۲۰۰۳ +دارای +ساخت +افراد +رتب +تازه‌واردان، +مه +محلی +بصب +بین +پتوپ +مقاله‌ها +نیازمند +اسلامی +۲۷ +بی +مرگ +علی +۲۰۰۵ +متون +مطلق +سه +می‌باشد +نیاز +شرکت +۲۹ +۲۰۰۹ +باشگاه +دلیل +زندگی +چاپ +موجود +۲۰۰۸ +نقل +گروه +۲۰۰۴ +انتهای +دارند +محتویات +شاد +موضوعات +جستجوی +۱۹۹۸ +مردم +نشان +موسیقی +ویکی‌مدیا +همراه +ویکی‌گفتاورد +تپه +شورای +دانشنامه +ویکی‌واژه +بدون +مانند +راه +شهرهای +فرهنگی +سیاره +ویکی‌نبشته +ترجمه +فراویکی +حجم +کنونی +طبق +ژانویهٔ +بار +اجرام +روستای +ویکی‌نَسک +تغییر +خوشامد +سرعت +۲۰۱۲، +جنگ +برابر +محل +سر +سپس +سیارک‌ها +عربی +بازیابی +داشت +بازی +ماه +می‌تواند +رو +کنید، +ژانویه +معرفی +بنا +مشترک +چندین +دوران +ندارد +جهان +حقوق +کنم +بالا +ضمن +داد +وبگاه +البته +آب +قدیمی +امکان +جمهوری +قسمت +۰۹ +مفیدند +پیدا +وپ +پروژه +بن +همکاری +۰۸ +تغییرات +كه +منطقه +معماری +چم‌وخم +معرفی‌شده +کنند +هزار +عرض‌جغرافیایی +طول‌جغرافیایی +۰۷ +روی‌نقشه +برخی +آی‌پی +آمار +ویکی‌پدیای +۲۰۱۰ +جای +موضوع +تمام +گرفته +شرقی +فوریهٔ +اخیر +قمری +متوسط +دیگری +غربی +درگاه +ربات +راستی +اولین +۳۱ +باستانی +امنیت +چنین +آلمان +کم +رسمی +جهانی +مطالعه +بررسی +ژوئیه +فعالیت +آغاز +آذربایجان +فکر +اين +الگوی +تیم +لطفا +ژوئیهٔ +صنایع +درود +نامه +تلفن +اقدام +روستا +ایشان +می‌کنند +فارس +حتی +تعداد +دربارهٔ +فعلی +درست +مدیران +گفتگو +حجت +دستی +ستاره +بسیاری +اند +نقش +کلیک +بودند +۰۶ +تولد +کردم +زادگان +شاه +متحده +توضیح +طول +دوست +ذکر +رسیده +مقاله‌ای +قابل +ا +اضافه +مسائل +ایالات +همهٔ +اینترنتی +نام‌گذاری +سیاسی +طور +خیلی +رضا +روستاهای +چپ‌چین +تولید +م +صفحه‌های +ص +برچسب +خانه +شکل +دولت +می‌توان +شامل +می‌نویسید +یادتان +موسسه +جنوب +نرود +نشریه +باشند +۰۰ +آمد +وارد +ه +فرانسه +جوایز +مجموعه +قانون +به‌عنوان +متن +د +۰۵ +جایزه +خبری +سید +ویکی‌خبر +گفته +اساس +سیاست‌های +جنوبی +سایت +آری +ممکن +نمی +بنویسید +روسیه +فیلم‌های +مهٔ +سوم +تشکر +جام +۱۳۸۵ +حدود +کامل +عرض +شمارهٔ +قاجار +ماني +عکس +اجازه +تصحیح +آرش +علوم +نظری +جای‌های +اشاره +دانشنامهٔ +گرفت +کردند +جان +فرهنگی، +مختلف +بانی +توضیحات +ارتفاع +موارد +میلاد +مثل +مرمت +ژورنال +شعر +محتوای +بیش +چرا +شمال +خواهر +می‌کنم +خم +فصل +شروع +تشکیل +چم +سرشماری +دهه +مشکل +ساخته +زبان‌ها +گونه‌های +مدت +مجموعه‌ای +زیادی +بهترین +درباره +موافق +دیرینگی +نتیجه +هست +آلبوم +ادامه +جهت +خراسان +شرح +ایران‌شهر +زیستی +پیشرفته +می‌دهد +راهنماهای +صفحه‌ی +افغانستان +هماهنگی +قلعه +اصفهان +بالای +جغرافیایی +شخصی +نسبت +می‌شوند +تصنيف +مطرح +عناوین +بوده‌است +۰۱ +۱۳۸۶ +زمین +سازی +حزب +سی +آن‌ها +سرشناسی +انقلاب +مي +واژه‌ها +مهم +سایر +می‌آید، +دکتر +مساحت +قطعنامه +۰۴ +شدند +مرد +درگذشتگان +پرونده‌های +باعث +نکاتی +اعلام +نامگذاری +پروژه‌ای +زبانه +سیستم +انتفاعی +یادداشتی +کتابچه +پرسیدن +۰۳ +چندرسانه‌ای +قول‌ها +هرکسی، +ویکی‌گونه +خوانندگانش +کیلومتر +سطح +زمینه +اهالی +ر +سؤال، +حسین +اصطلاح‌نامه +موقت +سندباد +بود، +تبدیل +سبک +بنویسیم؟ +روش +میثم +زمانی +۱۳۸۷ +دسترسی +کد +انگلستان +برنامه +رنگ +تحت +هاروارد +ن +مدیر +امیروبات +جرم +جلد +وقتی +گودال +نگاره +شمالی +۰۲ +پاسخ +آیا +تر +منتشر +شوند +انتشارات +مخالف +مسجد +بایگانی +هماهنگ‌کننده +کپی +متر +مجلس +۴۰ +دهید +شاید +آنجا +گل +کاربرهای +ناسا +دوستان +جناب +پیشنهاد +ان +دی +یافت +آسمانی +۱۳۸۸ +هنوز +نخستین +مذهب +نویسندگان +زنده +ایالت +ماسه‌بازی +احمد +آنهاست +کنار +شبکه +بازی‌های +مشخص +ژاپن +نمود +وقت +کشورهای +خواندن +معروف +اروپا +اشتباه +کرمان +سن +معرف +پهلوی +درجه +سوی +ام +محیط +بحثتان +روزنامه +گونه +۱۹۹۷ +طرف +کل +داستان +علت +الگوهای +آمریکایی +تو +آمده +بین‌المللی +داتک +امیر +انتشار +قوانین +شماره‌دار +دادگان +موفق +رشته +خاطر +دارم +خورشیدی +حسن +معنی +ک +زنان +انتقال +پی +حکومت +لازم +به‌آفرید +تپه‌های +نام‌صفحه +شابک +زن +قرن +دهد +عمل +بازیگر +تصاویر +رئیس +ممنون +عزیز +یاد +گفت +هفته +دین +رای +وضعیت +فرار +درخواست +سیاست +سمت +حالت +پسر +کوه +پرچم +طی +ادبیات +الله +کلی +کشف‌شده +بازیابی‌شده +غرب +فرودگاه +۱۳۹۰ +سپاس +واژه +توابع +ابعاد +کمربند +دور +مدرک +مبدا +مازندران +کننده +مدیریت +دوستدار +وجه +مهدی +نمایش +هجری +هنر +ابتدا +ده +رسید +اعضای +انسان +امام +مثال +دادن +آخرین +اسرائیل +قول +نمایید +حضور +رود +خودتان +زیاد +جا +توصیه +مناطق +عراق +مطلب +پرسش +خان +عضو +حسام +حداقل +باستان +ارائه +۵۰ +مواد +کمی +خارج +دما +چین +وزارت +اوج +خروج +طبیعی +پزشکی +ستاره‌شناسی +فراموش +پایین +کاری +اکنون +بعضی +میانگین +نشده +هزاره +نشر +مهندسی +شد، +آباد +خودم +اسپانیا +خاص +دوران‌های +۱۳۸۹ +جریان +منظور +طریق +ترتیب +بناهای +بیان +دارید +روستایی +سطحی +شیخ +نسخه +حرکت +بنده +سده +اجتماعی +طراحی +حرف +خودروهای +ویکی‌گزارش +نو +هند +استاد +به‌شما +دوباره +توان +نظامی +بلکه +سری +همسر +هنری +شیراز +مفیدی +جمع +علم +خانواده +انتخابات +آلمانی +فاصله +نیروی +مرتبط +نمونه +پدیا +فرمایید؛ +شناخته +چگالی +دیده +معتبر +مناسب +قرآن +میلیون +واحد +۴۵ +مهر +تبریز +هنگام +گسترش +طبقه‌بندی +۱۹۹۶ +فلسفه +کرمانشاه +گردید +گذشته +دنیا +زیرا +قدرت +مثلا +ببینید +لیگ +دریافت +انحراف +نام‌رسمی +می‌آید +حمله +گرانش +توسعه +افزایش +چشم +مکان +عدد +ابهام‌زدایی +دانش +موضوعی +نزدیک +شخص +آنان +دیگران +بازیکنان +آقای +کاشف +تلویزیونی +زاده +بسته +جایی +خدا +حاضر +شرق +می‌شد +حساب +پدر +داشتید +نقض +پیش‌شماره +ایتالیا +کاربرد +سعی +رفت +برد +‌بودن +کاربردها +تناوب +۳۵ +معمولاً +زبان‌های +بهمن +۳۲ +عباس +حضیض +پدیدآور +انجمن +فیزیک +نگاه +فعال +نور +نسخه‌ها +ریاست +هستم +فلکی +فرد +مسیر +اجازه‌نامه +جامعه +آلبدو +مصر +آنومالی +کلمه +نیم‌محور +بریتانیا +۱۹۹۵ +پر +پاک +ت +۱۹۹۳ +بازیگران +بخشی +فرانسوی +داخلی +خبر +سئوال +محمود +باشد، +امروز +کرده‌است +ارتباط +درصد +؟ +تاریخچه +ملل +اصلاح +معیارهای +همچون +؛ +طرح +شده‌اند +هدف +عالی +وقایع +میدان +محسوب +حل +باغ +استان‌های +خودش +قطع +ایران، +۳۳ +۳۴ +اش +دنبال +شهری +تعریف +دانشکده +انواع +دار +ورزشگاه +نقشه +کوتاه +شمار +ق +مدرسه +کمتر +آرامگاه +عصر +عبارت +بیست +تن +خرابکاری +المپیک +تیر +می‌رود +خیابان +بازار +نامزد +میرزا +داخل +اندازه‌تصویر +پایگاه +رضوی +سؤال +۱۹۹۰ +الان +گرامی +نبود +خوبی +۳۷ +خارجی +گیری +آورد +برچسب‌تصویر +۴۸ +سیستان +۱۹۹۴ +آزادی +رشد +نباید +پرسشی +۱۳۸۴ +حد +۳۶ +ملیت +رشدجمعیت +تازه +میانگین‌دما +عدم +نیروهای +تراکم‌جمعیت +سؤالی +نام‌های‌قدیمی +بنابراین +ارتش +شب +داشتن +علاوه +ابن +شمارروزهای‌یخبندان +میانگین‌بارش‌سالانه +پل +تصویب +میانه +خرداد +گیلان +سنگ +کنترل +بهزاد +کیفیت +می‌‌نویسید +۴۱ +درگذشت +علیه +گزارش +شیعه +خور +۳۸ +جزیره +ره‌آورد +دسترس +دستگاه +نام‌محلی +تگزاس +جز +همیشه +۴۲ +اجرا +کوشش +پخش +رد +۴۶ +متحد +اسفند +وزیر +خواننده +بهبود +اثبات +سفید +نظرخواهی +شرایط +جمله‌خوشامد +ترکیه +۴۴ +همدان +قم +۳۹ +می‌گیرد +۴۳ +بلوچستان +چیز +دسته +خوزستان +گنو +ترانه +کدام +خودرو +۵۵ +۴۷ +باقی +بندی +۵۱ +بخوانید +۱۹۹۲ +خواهند +صد +ناحیه +۵۳ +کاهش +۱۹۹۱ +میشود +مذهبی +۴۹ +ساختمان +اولیه +مقابل +۵۲ +سبز +وحید +۵۷ +مشهور +متوجه +تهیه +کافی +آنچه +ترک +افزودن +می‌شود، +جدا +۱۳۸۲ +چهارم +تقسیم +نژاد +معنای +کشاورزی +صفوی +براساس +سیاه +هایی +آسیا +تمامی +تحقیق +۱۹۶۰ +ساسانیان +نوشتار +رادیو +۵۶ +۵۴ +اسم +ارزش +دهانه +اقتصادی +ابراهیم +نخست +فرزندان +۵۹ +هاي +شهرها +دقیقه +حالا +دستور +امور +رابطه +پارک +جنبش +دختر +ج +قالب +بیماری +نام‌های‌دیگر +محوطه +بازیکن +کشته +دارد، +مشهد +منتقل +شهریور +مرداد +کیلومتری +پرداخت +۵۸ +تخصصی +۲۰۱۲ +مرده +دهیار +صنعتی +ش +خدمت +پشت +فشار +می‌کرد +تلاش +مدیاویکی +تلویزیون +میزان +سال‌بنیاد +قبلی +انرژی +بدست +نظام +حوزه +پا +بودم +یزد +پ +هفت +ازدواج +است؟ +فضای +نظریه +اختلاف +حمایت +خواهم +مجله +رفته +اجرای +می‌گردد +برتر +متولد +کره +خاک +برگزار +سرزمین +بدن +کرده‌اید +مسابقات +اقتصاد +ندارم +بعدی +قبول +خلیج +آخر +کمیته +فروردین +مادر +کارگردان +می‌کنید +سال‌ها +کسانی +مصرف +جدول +جشنواره +آنرا +دید +فرزند +عرب +کاملا +آمل +پادشاه +دیدگاه +آذر +اشکانیان +سفر +متفاوت +وزن +نیویورک +داشتند +بیشتری +موزه +یه +می‌رسد +خاصی +دل +دهستان‌های +آنکه +استقلال +پنهان +مجوز +نوعی +کردید +لرستان +جغرافیا +ترکی +محسن +هوایی +۱۹۸۱ +فروش +مقام +مقدار +۱۶۱۵ +قزوین +حالی +عمر +لزوم +میل +آبی +دقت +اصلا +اطلاع +رخ +شکست +اعمال +اینترنت +موتور +دومین +شهید +تحقیقات +تاسیس +برخورد +روم +ماده +محله +لینک +راست +امروزه +کرده‌اند +بازگشت +جواب +پارس +یونان +رتبه +ز +شده، +۱۳۸۱ +اساسی +نقطه +گردد +موجب +سخن +تقویم +نکته +می‌دهند +مستقل +جامع +اردیبهشت +هستید +سینما +مدل +کانادا +گاه +آورده +حفظ +ثابت +ـ +احترام +بوشهر +مربع +۱۹۸۸ +روابط +سیمرغ +درون +زیرنویس +کن +نظرم +ترکیب +بهار +بد +پادشاهی +دلار +شیمی +تعیین +بابل +نفت +دولتی +مدتی +نظرات +درستش +کاتالوگ +گاهشماری +لحاظ +ساده +بخش‌های +شوروی +باب +بی‌بی‌سی +گرفتن +دادم +مثلاً +گروه‌های +ندارند +کردستان +حاصل +شود، +انسانی +گرم +روشن +مسکن +خون +۱۳۸۰ +رسیدگی +مفهوم +خمینی +گیاهان +ساز +آهنگ +ترین +هرمزگان +۱۹۸۹ +صاحب +کارهای +اغلب +عبدالله +مشغول +۱۰۰ +شناسی +محمديان +گفتم +مختصات +دهند +یونانی +رایانه‌ای +یکم +ستارگان +کتاب‌های +ایرانیان +آوردن +صنعت +کند، +صحبت +فناوری +نمی‌شود +آینده +واگردانی +کتابخانه +برجسته +امر +نقد +مخصوص +بزرگی +آبان +نتایج +براي +یافته +لقب +متاسفانه +مالکیت +مشاهده +عرضه +کارت +گاهی +شش +دفاع +مایکل +اداره +خبرگزاری +دره +مسئله +صحیح +ولایت +گروهی +رودخانه +مقدس +مراسم +کشورها +باد +تاکنون +خلاف +علاقه +ارومیه +مرحله +ورود +۲۰۰۷، +تکمیل +موقعیت +رویدادها +تفاوت +ایستگاه +شیمیایی +مگر +ضد +ژاپنی +استاندارد +دریای +۱۹۸۰ +معاصر +زندان +غیرقابل +عملیات +دریایی +خصوص +برخوردار +لندن +شیوه +آقا +مشابه +سخت +خلاصه +دفتر +برنده +سنت +پاپ +جلوگیری +قدیم +ورودی +اسکار +بطور +چر +بندر +مرا +راک +نیشابور +نیستند +۱۵۱ +مشکلی +آتش +کشوری +تابستانی +امپراتوری +بررسی‌های +آن، +اس +میکنم +پارسی +تشخیص +شاعر +خدمات +س +عهده +نیمه +مشکلات +نیست، +آشنایی +بصورت +تأسیس +درمان +ابزار +آموزشی +نوروز +بروجرد +تواند +قتل +تحصیل +دیدم +مدرس +دانشگاه‌های +جمهور +محدود +برج +آبشار +دانشجویان +احتمال +رفتار +اعتماد +اطراف +هشدار +همواره +قطعنامه‌های +محمدرضا +پاریس +ساله +کالیفرنیا +وسیله +اصول +درخت +سالگی +۱۹۷۷ +پیشه +داریم +شخصیت +قصد +نداشته +می‌گوید +جشن +ویرایش‌های +ادبی +بهره +سنتی +فوق +کنید؛ +تام +آ +بانک +دهم +استرالیا +دقیق +نامیده +نفوس +فراهم +می‌توانند +بدین +اختیار +چشمه +دادند +يا +اردبیل +پست +خانوار +قهرمانی +منصور +سرخ +روسی +۱۳۸۳ +شبیه +بشر +قرمز +قطر +سبب +کشتی +برده +صدا +یکسان +شمسی +مجدد +اکثر +جالب +تک +گلستان +پنجم +فراوان +يك +نرم‌افزار +توهین +اتحادیه +عشق +ظهیری +گورستان +بلژیک +بکار +رستم +سرشناس +‌ها +هیئت +علیا +مقالاتی +رباتیکی +هنگامی +لطف +بختیاری +روح +ارجاع +تقریبا +۱۹۷۳ +ع +سپاه +‌های +یکدیگر +نموده +رمان +کرد، +جنسی +بزرگترین +پیشرفت +دعوت +بقیه +کلمات +شهرت +مرکزی، +رایانه +یمن +تخت +معادل +صادق +وسط +خوانندگان +تلفظ +اتفاق +امامزاده +تحصیلات +خانوادگی +حقیقت +خورشید +نوری +نقاط +پایتخت +بند +گوگل +مانده +نزدیکی +سعید +امید +نشود +نر +مسعود +سلطان +ادغام +سفلی +دریا +لاتین +اجماع +خوانده +سابق +ریاضی +درستی +فضایی +دلایل +برندگان +بعدها +متعلق +پیشین +شدم +هنرمند +درس +ذخیره +کارگردانی +نباشد +دانقولا +اون +تابع +مالی +صدای +بلند +بارگذاری +بخش‌ها +اینگونه +اواخر +ریشه +نشد +کاخ +ریز +فرض +قانونی +برق +جلوی +کودکان +نزد +قاسم +آهن +زنجان +نگارش +شدت +می‌گویند +جایگزین +جاده +می‌کردند +مفید +زرشک +لیست +محور +ویکیپدیا +رایج +مناسبت‌ها +خلق +مراکز +ساری +عامل +نقاشی +رسیدن +کارشناسی +۱۹۸۴ +خ +زده +رعایت +انگلیس +اطلاعاتی +ورزشی +مقایسه +منبعی +بازبینی +حافظه +حتما +عربستان +مستقیم +گیرد +الدین +۱۹۸۲ +علیرضا +تعدادی +ورزش +برادر +گذاشته +تهران، +محصولات +زندگینامه +هوا +۱۹۸۶ +۶۰ +کس +پوشش +حکم +قهرمان +خانه‌های +حاج +خواهش +گردآفرید +نوبل +نرم +رهبری +خیر +تجاری +نوشت +۱۹۸۵ +جوان +واقعی +نظیر +سند +سرانجام +منجر +اعداد +فی +واقعا +نبرد +مردان +جغرافیای +شدید +روند +ویرایشی +دشت +رده‌بندی +پرحجم، +گذاری +افشار +۱۹۷۸ +زدن +سوئد +خویش +ماهی +خالی +درآمد +آمریکای +مسلمانان +کجا +می‌باشند +طوری +اید +دکمهٔ +احمدی +درد +۱۹۸۷ +شاعران +گویا +نداشت +هـ +سالهای +ششم +شیر +دچار +تاثیر +زیست +دینی +سریال +نماد +راجع +مطالعات +مراجعه +لحن +خطر +پرسپولیس +حضرت +مکتب +دامنه +بروید؛ +زیبا +بافت +مسلمان +کامیار +محافظت +ناوبری +نهایت +کلیسای +هشت +تکرار +پرورش +توزیع +معمولا +وبلاگ +طولانی +تجربه +ظاهر +گسترده +ممنوع +پیروزی +چهل +گاز +عکاسی +کاملاً +احساس +همچنان +تفسیر +چک +مترجم +مشخصات +اینها +تایید +۱۹۷۹ +توکیو +ال +سمنان +۲۰۰ +رهبر +بیت +سومین +خورده‌است +پاکستان +۹۰ +همانند +فردی +ملحق +کامپیوتر +سوریه +پدرش +اوایل +پول +سوره +تقویم‌های +آفریقا +کتاب‌ها +دنیای +همانطور +دودمان +هدایت +باره +سلسله +موسوی +قضیه +غیره +صرف +آید +ايران +پک +طبقه +حاکم +داریوش +گوناگون +زهرا +اسماعیل +زمین‌لرزه +اعتبار +بعنوان +مُروا +توانست +۱۳۷۹ +تدوین +اهواز +سبزوار +جکسون +نمایندگان +مقاومت +آی +برداشت +گشت +قلم +تنظیم +نگاری +هلند +باور +نهاد +سینمای +تمدن +فرهنگستان +کردی +ویندوز +سوئیس +کانی +نویسی +ممتنع +مانی +پشتیبانی +جو +رده‌ها +ساکن +شهرک +روزی +صحنه +اصطلاح +تئاتر +جستجو +جلو +فردا +جیمز +کی +هرگز +چیست؟ +حمل +توصیف +گیتار +ری +والدین +۱۹۷۶ +حفاظت +رشت +سابقه +کودک +کنون +فعالیت‌های +عوض +اعتراض +نسل +دریاچه +مرز +باشگاه‌های +کهگیلویه +میکند +دادگاه +تصویری +خانم +مخالفت +نصب +آل +افرادی +چاه +نماینده +نگه +عملکرد +جدیدی +۱۹۷۰ +ي +مهمترین +آمده‌است +محمدعلی +بدهید +اتحاد +شرکت‌های +موج +رم +کشیده +تحلیل +نظارت +تابلوی +شهرداری +محصول +متعدد +نماید +قوم +مصطفی +جزایر +گرمی +عقب +صلح +شعار +ارسال +جی +نوشته‌های +غلط +۱۹۷۱ +سازنده +نکرده +مواردی +جوانان +حمام +دورهٔ +تبریک +بگذارید +دانشگاهی +مس +ماند +خداوند +مهاجرت +ضبط +ست +احتمالا +لبنان +دوربین +خودشان +عبور +ارشد +بنام +فرمان +عبارتند +مطابق +خرم‌آباد +بالاتر +سد +تقریباً +اکبر +دیدن +موفقیت +مدرن +نگهداری +۷۰ +عوامل +پای +جایگاه +۸۰ +ف +زادروز +پرواز +خلیفه +هفتم +ماشین +هرچند +هسته‌ای +عناصر +اسناد +گنبد +لا +نهایی +تدریس +طلایی +زابل +چندان +اروپایی +ظاهری +صفر +اول، +اشعار +دبیرستان +معلوم +برنامه‌های +نخواهد +زد +بیفزایید +خصوصی +وظیفه +ادعا +عزیزی +عمده +انتظار +آن‌لاین +قبلا +مبارزه +هستند، +خسته +فرصت +رفتن +مشارکت‌ها +گرامی، +سراسر +۱۹۸۳ +پیروز +گویش +رفع +جزو +گفتاورد +متال +مکزیک +۱۳۵۷ +امپراتور +اطلس +اسپانیایی +پنجاه +شاپا +بیمارستان +پیامبر +بستک +می‌کنیم +اشکال +تقسیمات +الکتریکی +درک +سلطنت +لباس +دهنده +نشست +اعدام +اقوام +شاخه +سلام، +الگوریتم +چپچین +شان +خواست +مدال +امارات +جبهه +باشم +مطبوعات +مستعار +نیازی +عادی +چینی +افتخار +کهن +نا +مثبت +شخصیت‌های +خطوط +ویلیام +سلطنتی +منطقی +اطمینان +جعفر +سقوط +روزهای +گرفته‌است +طبیعت +باشیم +رده‌های +ترتیب‌پیش‌فرض +شبه +موافقم +یهودیان +تربیت +دیوید +معاون +پرندگان +ملت +دیوان +تی +پلیس +ملک +نيز +هنرمندان +عین +تماس +حرفه‌ای +آستانه +بماند +واکنش +٬ +زحمت +عمان +حافظ +نیم +منفی +آسیای +تابستان +جدی +قابلیت +ساختن +آسیایی +رجوع +شهرستان‌های +معین +نیستم +ناشی +تهیه‌کننده +داشته‌است +دانشمندان +صبح +اعتقاد +مبارک +سورنا +اساطیر +اصلاً +تذکر +خطی +کاربردی +داشتم +آدم +کتابی +مختلفی +کاربرانی +سرباز +جذب +متغیر +وضع +روزبه +مجازی +گذاشت +بابت +اعلانات +مهمی +فلان +آماده +مصاحبه +باتجربه‌تر +رقص +کلاسیک +گیاه +سامانه +مجبور +نحوه +نبوده +نفوذ +متری +کانال +حیات +گفتمان +جلسه +ارادتمند +درفش +حومه +تصور +خاندان +بهرام +لحظه +برزیل +یهودی +دهخدا +ایتالیایی +رسانه +ل +۱۹۷۵ +مسابقه +خواستم +کابل +نی +اوکراین +موسی +شما، +بگیرد +زرد +هوای +فلسطین +اهداف +است؛ +ولسوالی +غار +بنای +نوشتارهای +مربوطه +اخبار +بودند، +مهم‌ترین +سینمایی +پیمان +۸۸ +همزمان +ها، +احتمالاً +آسمان +شهرک‌های +ابتدای +ندهید +بوجود +آیدا +جانوران +سده‌های +بازداشت +هسته +یادداشت +ایلام +نامی +مجموع +هنرهای +می‌دانند +ادعای +سرویس +بگویم +ظهور +هزینه +کاویانی +الگوها +ضروری +آرام +حذفی +اقیانوس +یی +امتیاز +زمینی +آدرس +باشه +امکانات +بیشترین +طراح +نواحی +مطالبی +مقالات، +بخاطر +لی +آفتاب +بفرمایید +دقیقا +هشتم +توانایی +آیت‌الله +مسیحیت +تبلیغات +محوطه‌های +بارها +ته +سنچولی +يک +الف +متصل +ساسانی +بویراحمد +سروش +نظرتان +ربطی +روایت +بروز +دیگه +پژوهشی +زبانی +۱۳۷۸ +ثانیه +برگزاری +تبلیغ +شاهنامه +نزاکت +قوی +خواجه +پوست +پژوهش +شروین +سنی +میباشد +سرد +بگویید +شکایت +بنی +صدر +مطلبی +اسید +کلید +خسرو +گذشت +طلا +شیرازی +اي +شناسایی +تأثیر +شیرین +می‌کند، +رأی +فردوسی +اگرچه +چهارمین +نمی‌کند +زاپاس +خشک +جنگی +برداری +قادر +بومی +بنابر +ديگر +تقدیم +حاشیه +نگاره‌های +۱۹۷۲ +اختصاص +یونایتد +بردن +اندیشه +حتماً +بودجه +داشت، +افزوده +۱۹۷۴ +بیرجند +عضویت +مستند +بحثی +الکترونیک +امروزی +بیرونی +فتح +معمول +واژگان +ادب +نمی‌توان +مرتضی +اتصال +مخالفان +گویند +ناقص +سفارت +۱۳۷۷ +المللی +قسمتی +چنان +مدفن +فضا +گرچه +ويکيپديا +آمدن +زیبایی +نوشتم +عهد +رای‌گیری +سرمایه +نامعلوم +ردیف +تجارت +نیک +ایل +یافتن +اظهار +گرد +مایل +اعراب +قیمت +چی +مقدمه +خرید +عمق +گمان +هری +معتقد +داده‌است +یوسف +مردتنها +بزرگ‌ترین +فراوانی +مرور +جزء +ناصر +موشک +رومانی +دانست +نادرست +خود، +فایل +تلقی +مشاهیر +بوده‌اند +آواز +ضمنا +بشود +عثمانی +مبنای +قلب +گوش +جمعه +آیت +ویرایشات +هاشمی +دارند، +استادان +فرق +همگی +پرتغال +ذهن +پیر +زیست‌شناسی +پرنده +بتواند +ارمنستان +اتریش +اندکی +آیین +اتاق +قطعه +شناخت +تغییری +۱۹۶۸ +عبری +معیار +هفتاد +روش‌های +نکردن +فاقد +آیه +دم +عید +مکانیک +تک‌آهنگ +نوبت +دیوار +گشتن +درمانی +مطمئن +نصف‌النهار +جنس +تیره +منظومه +بایستی +ریاضیات +مهندس +رییس +بارگذار +هواپیما +میشه +آرژانتین +کلا +کریم +شاهد +گر +سنگی +مسئول +نشانه +فیلمبرداری +نوکیا +جمشید +تغییراتی +کتب +کرج +استناد +شریف +ایرلند +اف +نسخهٔ +چهره +نوید +کنگره +منچستر +رابرت +نباشید +پرویز +مى +نماز +کمال +گونه‌ای +ژان +دلیلی +داری +عالم +اسب +حمید +قرارداد +پیشینه +قره +خروجی +کمونیست +قاسمیان +می‌گیرند +شصت +زمستان +کلمبیا +راهی +محدوده +نام‌ها +میر +لینوکس +میلادی، +بهداشت +اگه +سدهٔ +۵۰۰ +بجای +مغز +پوستر +حاوی +لغت +رسانی +لوگو +مسیح +فرزاد +فرمول +مؤسسه +مفصل +پدید +درام +اردشیر +آفریقای +خرابکار +تامین +داره +اتمی +بزرگان +محکوم +نجات +یادبودهای +ریچارد +رومی +مدار +تخریب +بدانید +درگیری +بیستم +افتاد +محترم +خودروها +نوین +مطابقت +تاجیکستان +نقش‌های +افزار +مراجع +اتومبیل‌های +عزیز، +ضعیف +امضاء +بیگانه +فرا +اکثریت +هرات +می‌یابد +پنجمین +میکنند +کنندگان +فعلا +۸۵ +نکات +ارتباطات +خواهید +مجمع +کنی +یابد +منطق +دیدار +دویست +دوستانه +آوری +آلبوم‌های +اتهام +بینی +مسیحی +گری +آنلاین +ویژگی +ادوارد +امنیتی +برایتان +كرد +دیگر، +عام +اصرار +بودید +تبلیغاتی +حاجی +هرچه +۱۹۶۴ +انتقاد +برسد +شک +توانید +ویژگی‌های +خوی +۶۴ +زادگاه +مساله +فیزیکی +هخامنشی +غذایی +نمی‌دانم +سامسونگ +گرفتند +تاج +موقع +۱۹۶۹ +فاطمه +سخنرانی +سختی +استدلال +۱۳۷۶ +شهردار +ار +سلیمان +متهم +مذکور +عملی +چندی +پدیای +صادر +منتظر +٪ +ضرب +تیم‌های +تل +حسینی +گیر +سراب +تیرداد +ویکی‌سازی +تان +مشروطه +کوچکی +مردمان +ویکی‌پدیا، +مجاز +محاسبه +بزنید +جنگل +مجموعه‌های +واقعیت +سان +قومی +صفحه‌ها +قطب +تالار +خواب +تاکید +گاه‌شماری +امین +لذا +آسیب +هیات +قد +میلیارد +کوچولو +برقرار +بالایی +شیعیان +قاضی +برگرفته +عنصر +معانی +ارتباطی +شبکه‌های +درود، +۳۰۰ +مراحل +لهستان +معمولی +نوار +محس +۸۹ +قبیل +سیر +دهیم +شاخص +عیسی +ترور +دمای +تکامل +کبیر +درگیر +سونی +یاری +۱۹۵۰ +آگاهی +نیوز +پیوست +رچ +خدای +کودکی +مرتب +رژیم +روبات +ابتدایی +میتوان +هشتاد +زادهٔ +کشت +بازسازی +وسایل +بتوان +مجارستان +پیاده +میان‌ویکی +فرمانده +۸۷ +تهدید +ویک +محرم +نهم +احمدی‌نژاد +۶۵ +خورد +رسول +تمیزکاری +بندانگشتی +گیاهی +سیاست‌ها +این‌که +کلیه +بهشت +هندی +مشکوک +فکری +عقیده +اشغال +نویس +ستون +خارجه +۱۳۸۶، +۸۶ +نمی‌گیرد +کارخانه +دانشجو +پیوسته +خاطرات +پادشاهان +۱۹۶۷ +غذا +زرتشت +سود +خوشحال +رساند +آر +فیلمی +می‌پردازد +تری +لایه +سپهرنوش +ظاهرا +مصدق +کویت +مال +احداث +کانون +مد +فرماندهی +مرحوم +مواجه +۱۳۹۰، +بايد +افتاده +دوم، +گردیده +کارل +وگرنه +ندارد، +ترجمهٔ +ساحل +جم +طرفی +نگهدار +شرط +روان +آبتین +جوانبخت +سازهای +الکترونیکی +پور +نود +جمعی +راحتی +حیوانات +داروهای +دستگیر +بابک +حداکثر +دانش‌آموختگان +حلقه +راستای +اراک +نادر +اثری +زبانهای +برندارید +رشته‌های +بستن +برگردان +آبشارها +ریزی +مراغه +دروازه +پذیرش +نمایی +مدیریتی +منصفانه +واژهٔ +جانب +متعددی +رسد +گوید +شغل +زاهدان +نمای +رواج +واضح +عده‌ای +می‌مانند +ایوان +چوب +نکند +فلسفی +معنا +نمی‌تواند +خورده +سو +باند +ماهواره +مرغ +دشمن +کوه‌های +سرطان +دبی +پرداخته +ایکس +آشکار +کاشان +بغداد +ببخشید +ششمین +منظورم +جلب +دیر +مـهـران +زند +مناسبی +خانگی +تجزیه +بالغ +می‌داند +علامه +جولای +برگ +سیستم‌های +سیستم‌عامل +کاوه +۷۵ +دراپر +مدارس +ظاهراً +رنگی +دهه‌ها +چیست +تظاهرات +مربی +سازمان‌های +برپایه +متشکرم +دوازده +ایراد +گیتاشناسی +می‌برد +اسامی +او، +دارد؟ +بورکینافاسو +تجهیزات +شاهزاده +دربار +دانم +زاویه +قاره +رهبران +گ +سرود +ابهام +۱۳۷۵ +ایمیل +پیغام +فرآیند +دالبا +ح +پستی +ظرفیت +بشه +سیتی +هستیم +پرتاب +کمدی +توی +فجر +این‌جا +گرگان +می‌دانم +جواد +شاتل +خطاب +الهی +گرایش +ملا +دانشمند +فیلتر +نسبی +شوم +داستان‌های +نمایشگاه +تربت +ممنونم +آگوست +پایدار +مشارکت‌هایتان +منطقه‌ای +تنگ +مقیاس +شریک +جزئی +هویت +بدهد +نوشتهٔ +بابا +ادیان +۱۹۶۵ +جورج +هفتمین +تصرف +آهنگساز +پاورقی +دلیلتان +حس +کوچه +رقابت +نمایند +رها +مقامات +منطقهٔ +قلعه‌های +فن +مادرش +متخصص +تکنولوژی +سالی +کیفیتی +زمین‌شناسی +می‌دهم +مک +کشتار +سنگین +می‌نویسد +نکردم +ید +پرو +بدان +باران +دخالت +درختان +جوانی +آنگاه +حسب +حرفه +سندی +چگونگی +تبار +توافق +کتابهای +اطلاق +نامناسب +مایکروسافت +۱۹۶۶ +ارشاد +فردوس +صوتی +روزگار +نمودند +سگ +دارو +خاورمیانه +معلم +گره +ون +سوخت +مترو +آموخت +نشده‌است +شماست +هتل +حدیث +نداریم +پیدایش +۱۳۷۰ +میانی +کنند، +عقاید +پیچیده +غ +قهوه +فرشته +نحوهٔ +عجیب +جداگانه +هشتمین +جزئیات +همشهری +مبنی +کاتولیک +اصفهانی +حملات +جاری +پویان +انگلیسی، +برخلاف +نيست +اشخاص +مجید +سیمای +کانی‌های +تغذیه +مربیگری +برنامه‌نویسی +‌پدیا +فدراسیون +اجرایی +سیصد +احمدآباد +می‌خواهید +جنگ‌های +پیگیری +حوادث +اخیراً +دیجیتال +تکیه +مریم +الی +۱۹۴۸ +كند +عده +اقدامات +شعاع +تخیلی +ماه‌های +۶۶ +آزمایشی +شده‌است، +واژه‌های +دشتی +موافقت +قهرمانان +جلال +اچ‌دی +الفبای +نفس +پایانی +پانصد +برایش +ترجیح +خواند +سلول +عصبی +کوخرد +آب‌انبار +۶۲ +مفاهیم +شنبه +بالاخره +دانسته +هواپیمای +نهمین +ایالتی +مو +فارغ +پلی +دروغ +اداری +استقبال +مسئولیت +داده‌اند +فدرال +ترانه‌های +نوازندگان +چای +دههٔ +تراکم +فهرست‌های +مردی +زمرہ +گورستان‌های +سوالات +عباسی +سردار +محک +ترکیبی +رقم +سعودی +نرم‌افزارهای +بازرگانی +برلین +نروژ +مارتین +فوت +دیدنی +کنفرانس +فارسی، +اهر +نجف +پذیرفته +اینست +ملکه +سرخط +كرده +زنی +قلمرو +بخصوص +امی +بهائی +نقاش +کازرون +تار +گرفته، +نظم +۷۲ +خودداری +شمس +صفحه‌ای +بیمار +واقعه +هادی +۸۴ +خاتمی +بارسلونا +سرچشمه +زنز +برچسب‌های +منتخب +بحرین +واشنگتن +پاتر +کرده‌ام +شاهین +زرین +مارک +توپ +وقوع +حدی +آذری +شاگردان +معبد +آرمان +۱۹۶۲ +بیماری‌های +بچه +فعالان +کوروش +دارویی +اوقات +اوست +می‌کنند، +قضاوت +ین +دست‌اول +فریدون +تئوری +نمی‌توانید +دوستی +حقیقی +زندانی +مقطع +راستش +۱۹۶۳ +شاپور +۱۹۵۶ +آکادمی +بازنویسی +ارمنی +۱۹۶۱ +مهران +مردمی +ندارید +گذاشتن +کوتاهی +فقه +تنکابن +درجه‌بندی +ژنرال +مایع +طرفداران +مدارک +بدلیل +پیشنهادی +باشند، +ذرات +دانشجویی +نگارخانه +نیت +کیلوگرم +سردشت +ایده +تسلیم +برادران +هزاران +حادثه +مرتضا +خواستار +نهضت +نرسی +آمیز +استودیو +قدمت +مجموعهٔ +مغناطیسی +قطعات +عمران +توجهی +فیلم‌ها +كار +۶۳ +رسم +درب +مبتنی +امواج +تمایل +احزاب +روحانی +ء +اردن +۶۱ +عمارت +می‌دانید +گفتار +دزفول +داوری +کا +حقوقی +زمستانی +فولاد +امریکا +مزرعه +بوده، +رساله +رامین +جراحی +محقق +ابزارهای +ویکی‌ +پزشک +قبلاً +ضلع +سرور +مجاهدین +اخلاق +گراف +مانع +مشارکت‌کنندگان +قشلاق +نوازنده +پرده +۱۹۵۳ +شیروان +کاظم +اریکسون +طیف +مسکو +۱۹۳۰ +۶۸ +مقابله +لوله +علی‌آباد +واقعاً +معدنی +طباطبایی +شاهان +تاريخ +ودر +ماهان +یوشیمیتسو +۱۹۴۵ +نمونه‌هایی +البرز +چهارمحال +مالزی +۱۹۵۸ +خودرویی +بیاورید +آبادی +مخابرات +می‌دهید +رودبار +جور +یحیی +كتاب +وین +می‌داد +غلامرضا +طایفه +سطر +خواهیم +جانشین +اقامت +توده +مشارکت‌های +برود +جویا +می‌روند +نتیجهٔ +اختیاری +اساتید +آگاه +ساوه +قدس +ناخالص +چرخ +پردازش +خرم +به‌ +کاربردهای +فیلسوفان +طب +زمانه +وحدت +افغان +منوچهر +طرز +بوسیله +مدیری +اخذ +اصلاحات +فرهاد +۱۳۷۳ +بایرن +تور +۸۲ +بست +راحت +تقلید +لهجه +قرون +افسانه +۶۷ +منزل +۰۰۰ +رکوردز +تأثیرات +افتتاح +بزرگتر +هندوستان +نقره +بهشتی +پذیر +عظیم +سیم +خواص +اعتراضات +سخنان +رزیدنت +مسجدهای +هرگونه +می‌آورد +این‌ها +دقیقاً +بسکتبال +صوت +بوئین +۱۲۰ +۱۵۰ +شور +زودی +توانند +سربازان +رویداد +خب +بنیان +چلسی +زیبای +شورش +خامنه‌ای +برایم +درخواستی +روان‌شناسی +جسم +ممنوعیت +اهورا +چقدر +ابوالحسن +سالن +صحت +می‌خواهد +۹۶۴ +نرخ +اختلال +رویدادهای +خراب +تونی +دایره +دبیر +۸۱ +۱۳۶۸ +دانشگاه‌ها +تقویت +زلزله +دهانه‌های +کوهستانی +محض +۱۹۵۴ +نبودن +بين +کارکنان +جملات +خاکستری +دادید +فرایند +دارا +وفيات +چهارصد +خصوصیات +چارلز +گفتند +ستاد +۱۰۰۰ +پیتر +انگلیسی‌زبان +مجتمع +وسعت +می‌شدند +۱۳۷۴ +نیروگاه +گذار +قوچان +تحصیلی +دهی +میلان +نمی‌کنم +فرم +پستانداران +گردن +۱۳۷۲ +۱۹۴۰ +جناح +شوشتر +پذیری +لیبی +اسلامی، +بحث‌های +سوء +همسرش +قفل +اسکندر +تحلیلی +تحمل +فعلاً +۱۳۵۴ +میوه +مصنوعی +ارزیابی +روزانه +مدعی +دانمارک +فرستاده +شناسه +صبر +شطرنج +گفتید +وسیع +گام +گوشت +کرده، +رصد +کوهدشت +اینطور +نوجوانی +ملت‌های +محمدی +۶۹ +لشکر +بزرگراه +۱۹۵۲ +پاینده +۴۰۰ +جانبی +ایول +تجدید +نیست؟ +حامد +نشریات +توماس +مجازات +قیام +گپ +سینا +۷۸ +بس +وظایف +کوهستان +اینجاست +میدهد +کارها +سالها +یادبود +آبادان +طبس +خوردن +روزه +مسکونی +اعظم +دموکرات +خشونت +۸۳ +هوشنگ +تخصص +سیما +منظر +علمیه +سالم +پیکسل +کمکی +خواسته +ایرج +مدنی +گفتن +آذربایجانی +ره +اتمام +آلاباما +۱۹۲۰ +ابی +بام +فقیه +کیلومترمربع +عوارض +۱۳۵۰ +ترس +بازگردانی +سعدی +موثر +کلیبر +انقلابی +وبسایت +روانی +موردی +دختران +روس +بم +پاک‌کن +داشته‌اند +یوتی‌سی +صدها +پانویس‌ها +نفتی +ورزقان +کمبود +نابود +فرانک +دان +۷۶ +جرج +جدایی +کیهان +نامش +تبریزی +کتیبه +حکومتی +قسمت‌های +صرفا +ك +۷۱ +اندازی +قدم +منحصر +عموم +پهنای +پدیده +روغن +رسانه‌های +اطلاعات، +سایت‌ها +اکران +سلامت +بالاترین +پیروی +۱۹۵۱ +مصداق +۷۳ +شکار +مباحث +پوویا +٭ +فاصلهٔ +فاز +۷۷ +حالیکه +شهریار +۱۹۵۷ +درخشان +آن‌جا +تنهایی +نکرد +عدالت +می‌نماید +مقبره +سانسور +داده‌ها +شاهرود +تخمین +نشست‌های +۱۹۳۶ +جین +روبرو +پس‌زمینه +نیرو +اخلاقی +داستانی +سینه +چ +شاهنشاهی +مولانا +گاو +استخوان +گرگ +دکتری +اند، +کشف‌های +سنندج +۷۴ +ساحلی +برهان +پیش‌نمایش +کردم، +دوره‌های +۱۳۵۶ +آغازین +سالانه +بستگی +تخم +۹۹ +سیگنال +ویکی‌پروژهٔ +ناقض +خودمان +کرد؟ +ویرایشگران +داوران +برداشته +۱۳۷۱ +یکمین +ریزشگاه +سوار +سلاح +شایسته +سفیدپر +غزه +ترکیبات +لاله +اولی +گذر +جک +ذیل +دراز +۹۵ +پان +درصورت +ایرانشهر +عرصه +پیروان +پردازنده +زایش +مدینه +انفجار +کمپانی +فرشتهٔ +واحدهای +حرارت +بعداً +۱۹۴۹ +همینطور +استخراج +ملاقات +فرو +پارامتر +منتقدان +آزمایشگاه +نوشته‌شده +اصطلاحات +بتوانند +مشتری +متوقف +اجباری +مسلح +سلجوقیان +کندی +اسکاتلند +فیلسوف +می‌سازد +زود +۷۹ +رجبی +هفتصد +تقی +معدن +مار +فراز +ایالت‌های +ایمان +ابراز +ممسنی +رادیویی +سرکوب +پیوندها +۱۹۵۹ +توزیع‌کننده +کشید +بال +۱۳۵۸ +۱۹۵۵ +شفاف +کلام +یکبار +رصدخانه +موسوم +صلاح +اخیرتان +کالج +واز +شیکاگو +جنبه +۱۳۶۹ +عاشق +کک +خنثی +امیرکبیر +آنقدر +زبان‌شناسی +مشاور +نمایشگر +دا +مِنْ +آرزوی +آئین +می‌آیند +شکلی +۱۳۶۰ +سقف +فرامرز +بحث‌ها +همت +خیام +تصادفی +میتواند +تجاوز +روح‌الله +روستاها +هواپیمایی +گلدن +منظورتان +کرمانی +قله +ضربه +ساکنان +اورشلیم +مجدد، +ویکی‌پ +معتقدند +۱۹۳۸ +محیطی +جعفری +خطا +ویروس +نگار +ث +سال‌ف +ابراهیمی +هشتصد +نکنم +ذوب +رایت +هاست +متنی +نان +اضافی +باله +اصغر +تایلند +را، +پیانو +سکونت +تالیف +اختصاصی +بهتری +ترابری +چو +دیو +زندگی‌نامه +شیشه +قلبی +تحریک +کیش +ستاره‌ای +اختراع +برآورد +سزار +دهستانی +مجسمه +برطرف +سپرده +پارلمان +رمز +درسی +سپاهان +منصوب +۱۹۴۱ +پروانه +جمع‌بندی +فعل +کربن +دژ +تفکیک +قفقاز +ۚ +همراهی +عبدالحسین +بسيار +مواليد +۲۵۰ +پیرو +معاونت +پیرانشهر +۹۱ +معنوی +کاروانسرای +دفن +سیزدهم +ند +اینقدر +هخامنشیان +دستگیری +گل‌های +می‌خواهم +گیرند +متفاوتی +شیلی +مراکش +کنسرت +بدهم +تومان +کهکشان +اوضاع +اندونزی +چنانچه +جایزهٔ +بدهند +کروبی +سکه +گرفته‌اند +می‌شوم +تضاد +ملایر +شیطان +سهم +اخطار +حرم +موافق، +هیتلر +واسطه +ناظر +نمودار +بگوید +تیمور +قصر +مکانی +فرودگاه‌های +۱۹۴۶ +جهاد +مقداری +داد، +اندک +دکترای +فیلیپ +۱۹۳۳ +کارگران +آماری +۹۸ +تست +ى +هستی +میزبان +تقاضای +اوبلاست +شیوه‌نامهٔ +من، +محتوا +مربیان +دیسک +معتبری +زدایی +صعود +حکمت +مخفی +زمینهٔ +دهان +گو +رمضان +ششصد +هم‌اکنون +شکسته +‌است +حرفی +۹۶ +هواداران +تبعید +نشین +توجیه +مکه +جاذبه‌های +منافع +بیفزایید، +عرفان +کشی +آمریکایی‌های +عقل +وفات +سیب +پربارتر +کنه +تألیف +بنیانگذار +دموکراسی +نهصد +یادم +سراسری +تفکر +لارستان +برگزیدگی +رباط +لس +حساس +حبیب +ویکی‌پدی +فرود +همکاران +تشویق +تحویل +باقری +داده‌های +معرض +گلوب +کلیسا +ویکی‌پد +کف +۱۳۶۷ +امضای +بخواهیم +خالد +فلزی +نظرخواهی‌ها +آیات +درگذشته +شباهت +هم‌چنین +تعلق +بگیرند +گوناگونی +نایب +حساسیت +کارگردانان +مغول +سازمانی +دیا +داغ +خواهی +فشرده +ماجرای +زندانیان +تصاویری +بیماران +کهنه +مکمل +بخواهید +رایگان +رویه +ماری +فرمایید +بلورین +فورد +درخواست‌های +سازد +پروتکل +راس +فرقه +وفق +نازی +احتمالی +طلب +اقماری +محدودیت +همایون +۱۱۰ +هیأت +احسان +ابرخس +بخواهد +له +مهرداد +می‌شوند، +سکوت +مهاجر +صدور +بازیگری +آسان +سراغ +اولا +محلول +وان +کوی +الکساندر +لیسانس +خزر +۹۲ +شکنجه +امیررضا +گرجستان +بازرسی +عکاس +۱۳۶۲ +آسیاب +گویی +شود؟ +حیاط +موجهی +ارکستر +ارباب +نویسندهٔ +یخ +السلام +نسب +بوی +۱۹۴۷ +نمي +اعضا +خانوادهٔ +ویکیپدیای +سحابی +شاهی +شیوهٔ +زیارت +تحقیقاتی +فعالیتهای +کاغذ +تهرانی +پروفسور +بریتانیایی +اخیرا +ایرنا +مادرید +۱۳۵۵ +زمینه‌های +ببینم +۱۹۳۴ +می‌بینید، +فیفا +صالح +متداول +ربط +سطوح +ی‌پدیا +خواهدشد +بحران +۱۹۳۹ +افکار +پیراهن +۱۹۳۲ +انتظامی +بلافاصله +ارایه +کمیسیون +راز +محمدحسین +آبیلا +محبوب +سایه +جوامع +داور +۱۹۰۰ +زودتر +ولز +سوخته +تأیید +ابوالقاسم +برادرش +بمب +امتحان +آرتور +فرستاد +صص +دانشجوی +کارگر +هوش +اتفاقا +غلامحسین +قربانی +می‌خورد +احکام +سرزمین‌های +ضمناً +فینال +قبرستان +ضعف +نامهای +گندم +قواعد +تند +تایپ +ماموریت +موسیقی‌دانان +گوشه +دری +مناسبت +ارقام +چاراویماق +مبانی +گذاشته‌اید +ابر +مدخل +یو +شناس +اندازهٔ +غالب +قنات +مبتلا +ویکی‌فا +نوزدهم +مونیخ +کابینه +میرحسین +باقر +۱۹۳۵ +سامان +هلندی +موجودات +فنلاند +برعهده +مدافع +قطار +تغییرات، +فرمانروایی +واگذار +حکیم +آهنگسازان +شوند، +تحول +مرکب +مقادیر +اختیارات +نوشتاری +چندانی +جان، +هکتار +رازی +محله‌های +آوردند +صف +مقاله، +تدریج +نیستید +تسلط +اسلام‌آباد +آزمون +ویرایشاتشان +اصولا +صفت +۱۹۳۷ +می‌شد، +سفیر +تمرکز +شهروند +نمودن +ویتنام +نمایندگی +گردش +سران +فر +ایمنی +خو +مشارکت، +پسرش +می‌ماند +متروی +ختم +علمای +۱۳۶۴ +ران +کودتای +قهوه‌ای +دایرة‌المعارف +لنگه +درونی +سرا +خاموش +منصب +ماد +دومی +کشور، +سوادکوه +خدایان +بی‌طرف +ماجرا +دماوند +بردسکن +ویکی‌نویس +ماهنامه +یادگیری +قابل‌ +هاشم +همگان +روانشناسی +محمدآباد +نگهبان +آفرید +گیرنده +۱۳۵۲ +۱۳۸۹، +ترکان +هوی +دندان +خوش‌آمد +گرفتم +پایهٔ +دانلود +جفت +فهم +گوشزد +متشکل +رسمیت +مقدماتی +جویباری +پيش +کنیم، +استانداردهای +سرجعبه +آنجایی +خیریه +بیش‌تر +في +دکمه +ماندگار +فیروزآباد +بخار +فیلیپین +جلگه +آرامش +۹۳ +رونق +پاسداران +میتوانید +کاووس +۱۳۵۳ +۶۰۰ +مرو +نیافتید، +نداره +نجفی +الهام +میکنید +ناصرالدین +قصه +آمدند +پراکنده +خواهان +روي +مرودشت +مسیحیان +عبدالهی +حسابی +پاییز +جانبدارانه +کی‌پدیا +حین +پلی‌استیشن +اعصاب +می‌توانیم +فرح +نمک +به‌طور +۹۷ +۱۳۵۹ +گرافیک +زمین‌لرزه‌های +منتهی +مستقر +تقدیر +۱۹۳۱ +می‌رفت +افسانه‌ای +برخط‌اند +آبشارهای +برخوردی +عکسی +خاور +مورخ +جمال +باتجربه‌ترند +به‌کار +مطالبتان +راه‌آهن +نفع +پاجعبه +نسخه‌های +بدی +آکادمیک +امتداد +یوشیچی +رضاشاه +تأمین +خواهشمندیم +لو +رئال +خراسانی +سردر +آشپزی +ایرانیکا +شاگرد +سرای +یزدی +نامزدهای +وکیل +نقشهٔ +اکسیژن +شفافیت +یکی‌پدیا +مقیم +ویل +یادآوری +بلوری +شعاعی +قائم +آلن +استانبول +بکنید +عمیق +تایمز +سلماس +بی‌طرفی +بیل +ۖ +بویژه +تک‌آهنگ‌های +می‌باشد، +جماهیر +وحشی +نمایشنامه +روایات +غنی +کسروی +بازتاب +شاملو +اروپای +برنج +بيشتر +اخراج +جمعیتی +اخترسنجی +شوش +خوشنویسی +تقاضا +مکان‌های +کریمی +۱۹۲۹ +دفاعی +برگشت +کنید؟ +معمار +خوش‌حال +قوه +۱۳۶۵ +اکسید +لاهیجان +آئیله +عقاب +پائین +سوالی +کنم، +مان +خواف +انجیل +محاکمه +ور +كنيد +میخی +مرزهای +روشی +بل +آداب +زرتشتی +باشی +جهرم +آور +شهادت +رسیده‌است +سادات +زحمات +بنویسم +شریعتی +بان +مرتبه +آثاری +شه +کابلی +تویوهارا +بیجار +می‌زند +نگران +کر +سیرجان +اماکن +ایلخانی +ماست +گزینه +دوشنبه +شواهد +قاعده +موازی +شتاب +۱۳۶۶ +حال، +ویا +می‌برند +۱۹۲۴ +نت +نجومی +تعارض +سادگی +۱۳۰ +خلافت +تأثیرپذیرفته +طبری +تعقیب +کاشانی +منع +توضیحی +دورود +حبس +بهایی +محاسبات +بگوییم +تنوع +معادله +۱۳۵۱ +کوچکتر +جوی +دورنما +شرایطی +فرماندار +هریوا +پی‌گیری +۱۹۲۸ +می‌نامند +ط +فومن +الجزایر +سیاست‌مداران +۹۴ +مقدم +طرفین +چمن +صفویه +یر +نابودی +رفسنجانی +معادن +۱۳۴۷ +نیل +سانتی +دام +نامه‌ای +ات +یافته‌است +می‌دارد +بقعه +۸۰۰ +پرتو +قید +ظرف +لری +قدیمی‌ترین +انسان‌ها +برنامه‌ریزی +وسطی +مسلم +چالوس +پیشتر +پوشیده +فرزان +میشوند +منظم +تلفن‌های +خوشحالم +تجمع +رنج +آباد، +مختصر +هماهنگ +روشهای +لفظ +چوبی +همين +شادی +وسیعی +گور +کردیم +تندیس +مواقع +الیگودرز +نسبتاً +هٔ +مخصوصا +شی +مشهورترین +می‌خواستم +انها +نهنگ +حرکات +دنباله +قانع +۱۹۴۲ +داوود +می‌کردم +جاوا +تعادل +پزشکان +نحوی +مادی +ردهٔ +گذاشتم +۱۳۶۳ +کمان +بعدا +شرمنده +ویراستار +ایام +اسلواکی +ناراحت +متحرک +تجربی +خاصیت +گیلانغرب +کشتن +مرزی +پرچم‌ها +ذهنی +لر +مساوی +رستمی +کرم +ازبکستان +رضایی +احیا +هنگ +توانم +شکر +مند +کمتری +بردارید +قبر +فرعی +ایم +معارف +پیوندی +اطلاع‌رسانی +بسازید +کردند، +کلیدی +سيستم +لغو +بسیج +سرنوشت +شاخه‌های +طرفدار +سیاوش +کشیدن +پناه +هشترود +ورزشگاه‌های +صفحه، +عارف +ابرکوه +،خرد +دراین +بایر +قلی +دشوار +بیزانس +بهانه +جالبی +قبیله +بیژن +چنانکه +می‌ +بیانیه +آلفا +کارگاه +استوار +کش +پویا +چیزهایی +نمی‌کنند +رهنمود +وصل +کریس +پسوند +مهاجم +جامعه‌شناسی +مجددا +ایر +احتیاج +متأسفانه +خودکشی +۱۳۴۸ +مراتب +یازدهم +خام +نوجوانان +بدانم +طنز +چهره‌های +شبانه +دامغان +مقصد +وزیران +لوح +شهرام +بده +جلا +دشتستان +روزنامهٔ +چهارشنبه +دالاهو +ضریب +تکنیک +سرخس +ولي +دکترا +آنجلس +خرس +مجتبی +نهاوند +مسیه +حسینیه +كنند +ملاک +۳۶۰ +هندسه +ابو +کامپیوتری +۱۳۴۵ +۱۰۱ +صندوق +بلی +آقایی +قالی +۱۹۲۵ +اشتغال +اوستا +خاش +باتری +قربان +رمان‌های +زير +خالص +زدم +باشد؟ +توقف +دوستانی +اجتماع +کوهی +کلاه +قائل +فلز +مطلوب +گربه +نگرانی +زوج +یار +سرپل +نوروزی +۱۹۲۶ +الآن +اختلالات +بریتانیکا +ايجاد +آزار +سا +پروتئین +بادی +مجزا +سانتیمتر +اله +پسران +۱۳۴۶ +دروس +کور +مطلع +نستعلیق +خطرناک +لوگوی +دنده +ویژه‌ای +بهینه +الکترون +سقز +عددی +کاش +جیرفت +راسته +بتوانم +نسبتا +یازده +کمیل +مانفی +انتخابی +نداشتن +حرکتی +کمترین +مرورگر +مقاله‌ی +برنز +انشای +فراتر +وسیلهٔ +انزلی +سوم، +آشور +اجزای +روزنامه‌های +نداشتند +برتری +توقیف +گنجایش +نویسندگی +واشینگتن +وَ +عبد +ماهیت +ترکمن +تابش +برف +اثرات +نمایشی +است‌ +حدس +بین‌الملل +۱۹۲۳ +راوی +بامداد +تنگه +گذراند +اتفاقی +هالیوود +گشته +اسمیت +باش +آلی +ترکمنستان +سوسیالیستی +مجلات +۱۹۱۸ +بدنه +قاهره +خانهٔ +بید +ایرانی، +۱۳۴۰ +پری +اشتباهی +نهاده +وب‌سایت +شهروندان +همایش +خوان +نژادی +عملیاتی +افزود +مخلوط +رودسر +الیزابت +نمونه‌ای +مغزی +قضایی +یان +گالری +بگو +ملقب +ایفا +انیمیشن +بخش‌هایی +شکستگی +سوپر +کانی‌شناسی +ویتامین +می‌دادند +پرجمعیت +درسال +۱۰۵ +ستاره‌های +مدیا +بندپی +تردید +كشور +ماهیان +پوزش +انگار +اسلام، +ايشان +سرپرستی +تاکستان +۱۹۲۷ +۱، +پذیرفت +نما +مشتق +باستان‌شناسی +امامی +اتم +ندیدم +نوشهر +گزیدن +۱۹۱۹ +حیوان +بنظر +کورش +اواسط +رفتند +تبادل +میلی +استون +دانستن +آمریکا، +حصار +آینه +گرایی +قبایل +کبیسه +۱۹۴۳ +۱۹۱۲ +۱۹۱۷ +برقراری +فيلم +نداشتم +سرده +فعالیت‌ها +بوستان +خیال +کارش +کربلا +کنم؟ +سیاست‌مدار +معنایی +آلودگی +شماری +کودتا +پانزده +المعارف +کالبدشناسی +عظیمی +علائم +کنسول +نحو +سوئدی +گرفت، +مازندرانی +مثال، +منسوب +نشدم +ویران +درخشندگی +بندرعباس +ارگ +سامانه‌های +بیمه +انجامید +اردکان +متمرکز +سلولی +مرسوم +صادقی +هيچ +امثال +ولتاژ +مقررات +رکورد +بلخ +نامزدی +پردیس +راه‌های +‌ای +مانده‌است +هدیه +خاکی +کلاً +كنم +جویبار +گرجی +سنجش +بو +مثلث +جمهوری‌های +خاتمه +رشتهٔ +بوش +حسین‌آباد +۱۳۴۹ +جنگلی +عزل +مزار +اختلافات +زاکسن +عشایر +دشمنان +کنگ +یهودیت +الگویی +فرکانس +تحریف +پژوهش‌های +شام +لار +می‌بینید +مریخ +علی‌اکبر +عامه +روزها +زخمی +عبارت‌اند +ویکی‌های +بری +کارائیب +رده‌فرد +رحیم +نگاشته +القاب +قاتل +مکرر +محمد، +ابداع +ویدئو +اسطوره +جامد +ژنتیک +مجاور +سیاسی، +رفسنجان +بعید +مرند +روحانیون +اریک +قریب +نثر +تحریم +موزیک +برداشتن +ارتفاعات +اشکالی +غذاهای +شهاب +بورس +سال، +نقشه‌های +عروس +نخل +محلات +آلبرت +فا +دشمنی +۱۹۴۴ +يكي +جایگزینی +تفاصیل +خدابنده +اقلیت +مشخصی +محاصره +زین +افتخارات +این، +بي +سواحل +اندام +فرماندهان +دانند +دوازدهم +بجز +آرا +بهائیت +۱۹۲۱ +کالا +استقرار +تلخ +تکه +جلوه +امان +نگونبانگونی +فیلمنامه +مترجمان +کتاب، +بستر +تولیدی +باغ‌های +نباشند +انصاری +محمدتقی +ان‌جی‌سی +سلمان +پهن +گستره +سودان +پرهیز +همون +موسسات +جاهای +اشرف +سواد +مصوب +دانه +اينكه +شعبه +تشیع +اپرا +مجری +موضع +۱۴۰ +گلوله +دارایی +آوردم +۱۸۰ +بلد +سیروس +گرمسار +مهارت +پیشاپیش +ساختمانی +باختر +نامید +ایفای +باریک +تعجب +عقد +فرمودید +وطن +گوی +قبرس +محبوبیت +کوچ +جدید، +اخترشناسی +کلمهٔ +ایذه +احوال +پراکندگی +ویرایش‌ها +سانتا +نپال +چرخش +فخرالدین +دستگاه‌های +پاراگراف +می‌توانم +پیکر +بعد، +جای‌ها +یاران +بیگ +پنجره +رامسر +خواه +انکار +می‌کشد +۱۹۲۲ +برعکس +پاره +اکشن +لغات +گردآوری +سهراب +نیز، +عراقی +پاسارگاد +نوجوان +مخفف +هیچگاه +کاندید +بهروز +بناب +تهمت +آفریقایی +جسد +پژوهشگران +موسس +بلاگ +آبخواره +مایه +مجدداً +لقب‌ها +تلسکوپ +استانی +منتقد +داراب +دلخواه +فرش +بارگذاری‌شده +صحرای +نوک +فارسي +رسانه‌ها +ماکو +۱۳۶۱ +استفادهٔ +دستیابی +سرو +بردار +آلبوم‌ها +مکعب +تب +می‌گرفت +وی، +قطعی +اقبال +پلاک +برابری +جوش +التحصیل +بردند +شارل +خشم +سارا +گناه +حوصله +بیافزایید +اصیل +خودمختار +نمی‌دهد +داند +سراوان +صور +یعقوب +شنیدن +اشتراک +دفع +اد +ه‍ +وستفالن +بهائیان +پناهگاه +مسیرهای +هست، +مذاهب +گران +تابعیت +یابی +ولسوالی‌های +اسرائیلی +تاریکی +تعطیل +همکار +زور +خلیل +شوخی +سلول‌های +تنش +کرسی +نصف +می‌افتد +بیات +فضل +نامشخص +تعبیر +۷۰۰ +شو +سوسیالیسم +اب +پرچمک +دموکراتیک +تحولات +بگیریم +گسترده‌ای +آریایی +کیلو +والی +براون +ناچار +گنج +بلندترین +انگشت +محتواهای +۱۳۸۵، +نه؟ +یهود +وضوح +بلوک +بلور +باکیفیت +غير +بدل +نادیده +لاریجان +دلفین +جاز +حاکمان +دوری +آرای +خاوری +شناختی +ماریا +شیب +نیوزیلند +مشکین +منتظری +خریداری +۱۱۵ +جانی +به‌شمار +تعلیم +تأکید +اندازه‌گیری +یافتند +مادری +فون +بادن +کدهای +بدنی +لوئیس +ادامهٔ +مبلغ +صلیب +می‌بایست +آریا +۱۲۵ +بفرمائید +قراردادی +شر +گفت‌وگو +گرینویچ +مولکولی +نیو +سايت +۱۹۱۴ +جزیره‌های +رسیدند +فرمت +قائم‌شهر +تفرش +نظریهٔ +خواستید +هافبک +دائمی +تنیس +می‌دهد، +ماتریس +باخت +سیا +مغرب +سل +اسلحه +ذهاب +دهد، +فرقی +صرفاً +وبلاگ‌ها +نمیشود +راضی +آتن +چراغ +حالتی +شلیک +الیور +اینکار +برپا +آهنگرکلا +لویی +نیما +بجنورد +نهادهای +محروم +نکا +لب +وحش +اعتراضی +ژن +ويكي +عثمان +نیشابوری +بلک +کنندهٔ +موتورهای +رئیس‌جمهور +حکایت +حاکمیت +نفره +هرسین +مالیات +انجام‌دادنی‌ها +خودت +مناقشه +کارهایی +غذای +نوردراین +علل +دیپلم +دادگستری +پیچ +لیورپول +سرپرست +گلی +تفت +جنسیت +امری +صبا +اسفراین +ریخته +برا +ناپلئون +دبستان +ویدئویی +خمیر +انتخاباتی +گفته‌است +ورزشکاران +عادت +آرایه +اعتراف +استخدام +آرامگاه‌های +دوتایی +ارنست +عمدتا +مجهز +زدند +۱۳۳۰ +۱۳۸ +۱۳۳۲ +آلبانی +نشانه‌های +باغین +شعبان +فارسی‌زبان +نیمی +سازگار +زبانان +پیست +کارایی +گرافیکی +کوره +اتیوپی +ساوجبلاغ +مشرق +فِي +سیزده +۱۰۳ +مردم‌شناسی +بلندی +محمودآباد +بتا +۱۰۲ +مراد +افتخاری +سهام +امیدان +دلایلی +غول +۲، +مازیار +عمدتاً +مملکت +۱۳۴۲ +انگیزه +فرنگی +مینودشت +بقایای +ابوالفضل +فاکس +میگوید +همچنين +شعری +لس‌آنجلس +تائید +تاریک +تونس +بستان‌آباد +کارمندان +اسحاق +۱۶۰ +کارگری +پتانسیل +سحر +۱۰۹ +نیازهای +آرسنال +افزون +نظریات +کوبا +فهرستی +آزادگان +کارشناسان +تزریق +کاپیتان +حدودی +فیل +والیبال +ازای +این‌گونه +همانگونه +نداده +سردبیر +تالش +سام +می‌گذرد +آنتی +مجلهٔ +بازی‌ها +رجال +هم‌درازا +دختری +رفته‌است +ابریشم +فلوریدا +بلغارستان +مصری +بلوار +دليل +راه‌اندازی +۱۰۴ +شمشیر +ندا +صادرات +دانیل +هریس +کله +حوزهٔ +نشسته +بیاندازید +۱۲۸ +وبه +تازگی +شورا +سروده +درمورد +شدند، +قطعا +اراضی +می‌گویید +حامی +خوراکی +جایزه‌ها +کویر +مفهومی +رودهای +زمان، +کمیاب +مخاطب +سوابق +سلامتی +علوی +خواندم +نهایتا +هوشمند +همیشگی +همدیگر +سازه +ترویج +مقر +قشم +تغيير +دیروز +مخالفم +نجوم +آرزو +عموماً +افقی +گوشی‌های +رباتیک +کلاته +لورنس +وزیری +پرداختند +رجب +جوزف +سپری +تایوان +مقاله‌هایی +بود؟ +بزند +مرسی +باختری +صلاحیت +نمی‌آید +بهشهر +جماعت +خونی +نوشته‌است +ازنا +مکانیکی +فضاهای +فرمانروایان +رزمی +همسایه +همدانی +۱۹۰۸ +۱۹۰۵ +هردو +۱۱۴ +هرم +شهرکرد +۱۰۷ +آب‌های +متقاعد +شویم +نبود، +نویسان +هم‌زمان +شهر، +صخره‌ای +ارزشمند +۱۳۲۰ +حذفش +سامی +ثانویه +دن +احساسات +بوئینگ +نام، +شبکهٔ +شمرده +طوایف +باری +جبر +اجازهٔ +بزرگ، +بهم +۱۱۱ +جهان، +مولوی +تفریحی +ماساچوست +آنها، +اجتماعی، +طاق +خوشامدید +نیامده +اچ +ملاحظه +کمبریج +زی +برش +می‌گذارد +شدگان +بدو +درحال +چارچوب +شده‌اند، +قطبی +لئون +هیدروژن +کاردانی +درمیان +نقاشان +شنیده +چنين +آتشکده +کوههای +قروه +هجوم +سرهنگ +عکس‌های +تاجگذاری +خرج +۱۳۴۴ +جعلی +آمیزش +راهپیمایی +سرشار +فیروز +دوک +بهداشتی +شکی +ماهواره‌ای +طاهره +زیرصفحه +تسخیر +مخزن +حیدر +اتفاقات +غزل +زهج +بولیوی +کردها +۱۹۰۱ +قند +نخست‌وزیر +بازهم +عصب +مهاباد +پرس +گازی +ابزاری +مبدل +۱۳۵ +میشل +مستقیما +صدام +محکم +فلزات +طنابداران +پروژهٔ +امّا +صحرا +۱۰۸ +جملهٔ +شوهر +هواپیماهای +سعادت +جعل +صفحه‌کلید +اوباما +۱۹۰۶ +انب +اپل +مرخصی +معیارها +دانید +دعا +تلفات +تضمین +آرامی +دائم +شد؛ +چرخه +شجره‌نامه +آفرینش +معادلات +رسما +مزبور +بارش +برکه +نبی +مصالح +والتر +سدیم +بحثش +پیشگیری +پروین +نشود، +می‌گردند +مسافر +راین +بتن +خوشه +طوسی +جونز +وابستگی +اسیر +خیابانی +بت +اینجانب +ببینیم +لیکن +بگذاریم +شراب +انگیز +برروی +حاجی‌آباد +پارسک +اعزام +اعطا +فقر +علي +کارنامه +حجاب +اینک +جمع‌آوری +درهم +خواهشمندم +اینه +گانه +پارچه +گردیده‌است +مداوم +آلوده +حقایق +جعبه‌دندهٔ +بشری +چهارده +۱۳۰۰ +لیلا +بدیهی +مابین +مثنوی +ویدیویی +محققان +رابط +تلمبه +پرفروش‌ترین +استیو +ساختمان‌های +وانتشار +معترضان +وحی +برنامهٔ +بگم +عسل +پرتغالی +فصلنامه +عجب +رفتارهای +وورتمبرگ +امپراطوری +برون +شانزدهم +مدل‌های +آکسفورد +فساد +چیزها +خبرنگار +ذره +کان +کنیم؟ +دامداری +هی +عبدالکریم +کوهرنگ +آنتونیو +ایرادی +۱۱۶ +دریافتی +هرمز +آب، +گـپ +ویکی‌پدیایی‌ها +۱۰۶ +غریب +دلفان +راسل +۱۹۰۷ +گویم +قزاقستان +وحشت +منشور +انتقام +مشروطیت +کیفی +بپردازد +براى +شركت +تعصب +ویلهلم +خطای +متقابل +۲۰۱ +اشکانی +می‌کرد، +بروجردی +طبقات +طالبان +سفارش +فیلمهای +آهنگ‌های +کنستانتین +پیوستن +دیدگاه‌های +چالش +ستایش +نقشی +کهریز +منطقه‌های +خلبان +تنگستان +فروند +حج +خاتم +۱۳۴۱ +گردند +پایتون +گفته‌اند +دانسته‌اند +دانشکدهٔ +تکلیف +بازرگان +نتوانست +بیوگرافی +۱۵۰۰ +بنت +مری +نقص +فانتزی +پژوهشگر +دویچه +کنت +قاجاریه +دوام +حیدریه +جیمی +پویانمایی +قوای +می‌آورند +کامران +متنوع +استراتژی +شمارش +۱۹۰۴ +اعم +داراي +بهبهان +الدوله +تخلف +فراری +ایزد +رأس +انداخت +چرداول +پیش‌فرض +رهنمودهای +بافتا +شناسان +اردو +آبیاری +ترانه‌سرا +روحی +ادیب +فلات +ایست +سلیقه +ماجراهای +باکو +همارس +تراکتورسازی +گم +رابطهٔ +داشتند، +رپ +گز +بگذارد +۱۱۲ +مستندات +زمین‌های +سایت‌های +مبحث +مشکلاتی +بوکان +ابزارها +جبران +تقریبی +زیان +گلپایگان +خوشنویسان +۱۲۲ +بارز +مَا +بوک +اشتباهات +تانک +می‌شده +دهه‌های +واژه‌نامه +خشکی +ایی +اللَّهِ +عفونت +۱۲۳ +باده +نام‌تصویر +بیس +كردن +گچ +زدهٔ +طلای +معکوس +نبودند +رضایت +ثروت +انار +کشاورز +کوانتومی +اژدها +سوراخ +بیلبورد +شاهین‌دژ +بره +اهدا +زیرزمینی +تکراری +صربستان +مراقبت +تروریستی +۱۹۱۱ +متمایز +آملی +برساند +عن +ابهر +معتدل +گفتگوی +املش +می‌بینم +می‌آمد +۱۹۱۳ +ناشناس +وله +جایش +جنبش‌های +توليد +موزه‌های +نمائید +دهمین +برند +تاریخچهٔ +می‌شده‌است +پاسخی +پشتی +تشریح +نمی‌شوند +خویشاوندان +انگشتدان +دكتر +ژانر +فریاد +اخلال +تمشک +سعد +پارسا +۹۰۰ +نامدار +نظامیان +قدری +حمام‌های +مستوفی +گرما +گرا +یادگار +عاشورا +دفعه +بیانی +شنا +استعفا +رسانه‌ای +انحلال +بزرگداشت +فایرفاکس +بتوانید +مؤلف +حامیان +ناحیهٔ +مور +۱۹۱۰ +حیاتی +هرگاه +آنا +جاسوسی +منتج +جابجایی +تولیدات +هاى +قدردانی +۱۷۰ +راست۱ +لیلی +عملاً +میشد +کشورهایی +درجهٔ +حامل +ابوبکر +خصوصا +اختصار +مجاورت +پدیدآورنده +آراء +چپ۱ +گله +یکپارچه +عبارات +جمینای +جزیرهٔ +اسرار +خانواده‌های +بلوز +مونته‌نگرو +بیابان +به‌صورت +دارید؟ +نقطهٔ +ضرورت +وي +کارکرد +هوانوردی +محبت +پارک‌های +واژه‌ای +امامزاده‌های +هریک +کوچکترین +طاهر +حوالی +مطهری +کنگاور +شدهٔ +شبکه‌ها +شیوه‌های +تیراندازی +۱۱۸ +جست +آژانس +سایز +بدن۱ +تکذیب +نقدی +متناسب +دال +بابی +شانزده +هرکدام +ادعاهای +العاده +عنایت +مزدیسنا +انقراض +مقدونیه +۱۲۷ +ندیده +رأی‌گیری +دلو +هندسی +موبایل +تورم +رفتاری +پیامدهای +زید +زادروزها +حیدری +بتوانیم +فوری +علایم +نویسه +غم +خلال +اریل +کاشمر +بز +بردسیر +۱۹۱۵ +حتا +برخط +خرمشهر +همچین +نفری +سالگرد +متخصصان +شاهرخ +صحن +جنین +جشن‌های +یکشنبه +تمیز +ارامنه +چپ۲ +جلسات +مهمان +کجای +روال +۱۳۴۳ +پینک +سبک‌های +هان +بدن۲ +عمودی +افسران +شجریان +نوسنگی +الاسلام +مساجد +صاف +مروارید +جانور +آنهایی +راست۲ +اسکی +ناشناخته +اعتقادات +یم +انگور +ويرايش +گروههای +ترانهٔ +شد؟ +دقیقی +استادیوم +مختلف، +عتیق +توطئه +بالا، +مین +همگانی +تلفنی +می‌دانست +ود +ميان +تشکیلات +روده +مدیره +ونزوئلا +مخصوصاً +مشتمل +انتقادی +تفنگ +برایشان +طالقان +فرانسیس +بازارهای +پایین‌تر +کاروان +به‌جای +الیاف +خامنه +خصوصاً +ظهر +سکس +چهاردهم +ایزو +مسجدسلیمان +الکل +فلاندری +محمدیان +شکوه +کرده‌اید، +اسلامي +سم +کناره +لوازم +نمیدانم +پیامی +فارغ‌التحصیل +باس +کام +بنویسد +بازنشسته +نصر +کاشی +شکارچی +پست‌های +ویلیامز +دهکده +اندر +۱۵۴ +جهانگیر +ملکان +می‌توانست +عبارتی +مسئولان +هلال +مهندسان +غارهای +بیلی +۱۹۱۶ +بنگلادش +حملهٔ +توانستند +پارینه‌سنگی +پولی +خوشبختانه +نموده‌است +امینی +نه، +هما +مشورت +نامحدود +آندره +پلنگ +مخدر +مضمون +برمی +هم، +لاس +دهید، +ویکتوریا +موثق +داود +عذرخواهی +یاهو +رنگ‌های +۱۱۷ +تناوبی +نوشتید +لااقل +شتر +مرکزیت +امن +ترسیم +سیستم‌ها +اتومبیل +آفی +جون +خالق +حرارتی +رسوم +موریس +مارشال +یورو +بانو +اولين +منشورات +غیبت +نوشته‌اند +قدرتمند +شکم +هایش +انداز +رویکرد +علاقه‌مند +خانواده‌ای +دمشق +دربند +برو +آرشیو +۱۹۰۹ +رویش +استخر +آنالیز +گچساران +بکنم +مولا +متفرقه +رحمت +شاخ +۱۳۱۰ +اتفاقاً +اسمش +سهامی +دبلیو +بخشهای +سرتاسر +ویکی‌ها +خیالی +نکنند +تناسلی +م‍انفی +جديد +۱۳۲۴ +کار، +برندهٔ +پیچیدگی +گواهی +زرتشتیان +ناصری +همانجا +رغم +گفتهٔ +۱۱۳ +گرمسیری +طلوع +برترین +درآورد +به‌دست +برقی +سپاهیان +ویژگی‌ها +مر +۱۲۴ +چهاردانگه +جامعهٔ +تحقق +مجاری +می‌گفتند +فروپاشی +چشمه‌های +ساختاری +مسافرت +پیکان +نرم‌افزاری +جد +روشنی +معرفت +تله +می‌کنم، +محرک +مشتریان +بیانگر +سازمانهای +چیزهای +رقیب +فرعون +بیروت +منعکس +تابناک +مشرف +آورده‌است +نمی‌توانم +۱۱۹ +مولکول +نعمت +می‌رساند +فرمانداری +دستکاری +۱۳۳۹ +مت +اردبیلی +مسدود +بله، +رانندگی +۱۲۱ +سایپا +استعداد +پیامبران +داماد +واجب +نسخ +فاضل +عرفانی +بزرگ‌تر +حق‌تکثیر +شخصاً +دگرگونی +عكس +انبوه +آپولو +فنون +افلاطون +حمزه +میانجی‌گری +نظرسنجی +آنتونی +اکوادور +آن‌چه +قذافی +اسکن +خاتون +ناگهان +گونه‌ها +تونل +به‌ویژه +ناگهانی +بدهیم +دوشیزه +آباده +نمی‌توانند +شلوغ +ی، +۱۳۳۵ +خلع +فلوید +ابومسلم +بایت +اعطای +جاسک +پوند +پایداری +تیتر +واپسین +استالین +تعطیلات +آستین +مختلط +تابلو +خنده +نویسه‌های +ثمر +۲۰۰۰، +بازاریابی +حسابداری +تکلم +رنگرزی +نهبندان +۱۳۳۶ +نیلوفر +شرقی، +بداند +فسا +آلیکانته +دیلمی +اجتناب +نیر +سطح‌بالای +اينجا +می‌زنند +کیم +لغتنامه +عاشقانه +فتحعلی +اشیاء +تعمیر +فلانی +استیون +سازماندهی +ویرجینیا +راجر +بگویند +روزنامه‌نگاران +هندو +دیوانسالار +ایستاده +۱۳۳۷ +کرانه +کلسیم +هایدلبرگ +کرواسی +سرانه +الملک +سنگ‌های +ژنتیکی +نیکی +هجرت +مامور +خنک +نمایان +بهرامی +شبستر +واسط +آرایش +مبهم +بسی +بریتانیای +محدودهٔ +بحث‍ +گاما +ده‌ها +نواختن +فروشگاه +خمین +صنعاء، +کنفدراسیون +اموال +هنرپیشه +پارسیان +متوسطه +دامن +۱۲۶ +لک +شیشه‌ای +ابراهیم، +آمادگی +هو +زنجیره‌ای +۱۳۲۸ +بازیهای +سنقر +بدر +آورند +مرجعیت +آلت +اسدآباد +کارلوس +سودمند +نشانگر +رسید، +حوزه‌های +دیار +کنگو +میهن +کلانی +۱۲۹ +افسر +باکتری +معماران +۱۳۲ +سیدنی +کفش +ارادت +می‌خواهند +خر +۳۵۰ +بدترین +تاریخ، +فلسطینی +زاگرس +بیاورد +یانگ +شخصا +تشدید +آدمی +ماهی‌ها +هیچکدام +میناب +بوسنی +ایندیانا +دنباله‌دار +ملوان +روزنامه‌نگار +مؤثر +دستورات +رطوبت +تعامل +کلان +عباس‌آباد +کاملی +احادیث +مدرکی +پاکسازی +۱۳۷ +تفاوتی +ورزشکار +جنبه‌های +غالباً +بود؛ +چنگ +مهاجران +پله +تراز +آمد، +وا +ژ +کوثر +وادی +اتوبوس +کاظمی +خبرگان +موس +تکمیلی +لهستانی +درویش +منم +جعفرآباد +نیا +جاذبه +گیلانی +طلاق +تروریسم +به‌خاطر +آيا +گرفتار +اشعه +می‌پردازند +شخصیتی +آقایان +رفتم +جریمه +مهره +خاستگاه +میان‌ویکی‌ها +بالینی +یزدگرد +ببرد +دوش +چغازنبیل +۳۰۰۰ +فوقانی +۱۳۳۱ +گیلکی +خط‌به‌خط +کاترین +بختیار +کردید، +گردان +ادی +طاها +مدیترانه +ارس +حسن‌آباد +پوشاک +بابلسر +رساندن +کند؟ +بهش +وست +خوشامدگویی +مهار +میبد +فلسفهٔ +وند +آش +سیمین +خوراک +خوزه +ساختند +نياز +عروسی +میگردد +جلفا +بودیم +بکند +۱۳۸۸، +روحانیان +حماسه +پایتخت‌های +مبارزات +احمد، +ارث +محمّد +۱۳۳۳ +کوشک +سنگ‌ها +زشت +دنا +دستیار +گرمایی +ایشون +نامهٔ +تحمیل +گوشی +دوره‌ای +ققنوس +بدانند +شن +انداختن +هفدهم +غالبا +اسدالله +۱۳۴ +شدیدی +ناپذیر +۱۴۴ +گینه +سرمربی +نطنز +کیبورد +محفوظ +آیند +انفرادی +آن‌که +گمانم +توانسته +سال‌شهرشدن +علم‌جو +خرده +درگز +ایستگاه‌های +بکشید +پیش‌بینی +حالات +هرکس +بزودی +کایروس +اوستایی +صفات +مارکسیست +خشت +جنب +عذر +ونیز +آسانی +کریستین +صفویان +اسدی +۱۹۰۳ +تاخیر +خیانت +قوس +قطره +آثارش +سیل +اسکات +مشاغل +شم +بخارا +چاپی +مکتوب +دیدید +انتها +موزیکال +كاربر +منشأ +سمی +لَا +پهلوان +پوسته +درختی +مشابهی +کنیا +عاملی +۱۳۹ +گویید +۱۳۳ +تلاش‌های +اهمیتی +عازم +اسمی +پکن +تصوف +تکاب +حاکی +برت +کنيد +نوروزتان +ببیند +کبوتر +سفرنامه +۱۳۳۴ +تخلیه +آق +زنجیره +انتقادات +کوک +همان‌طور +غربی، +جنجال +فیزیولوژی +سانتی‌متر +بسط +زخم +۱۴۱ +ویکتور +آران +یك +التهاب +دسته‌بندی +جنگنده +ایفتا +ژاک +طاهری +فیض +بهتره +ادعایی +اسد +بودنش +پیک +مسأله +بانوان +بنفش +گشود +باغی +هیدوچ +جسمی +انگشتی +یوهان +لنز +چراکه +رهایی +نگرفته +مقصود +جوراب۱ +آنهم +قمی +سکته +کو +سره +زبانها +برج‌های +مکان‌ها +نشدن +چابهار +پاراگوئه +کتابها +طولانی‌ترین +اولویت +مبارز +استراحت +مشت +حرام +فرمود +نقلیه +کمر +پستان +سرچ +فعاليت +ارتقاء +شانس +خودی +فاتح +مطالب، +گوسفند +میگویند +غلام +وصف +دلم +اظهارات +انتگرال +سوسیالیست +گذارد +ماموران +بادام +چال +ساگه +ایسنا +معده +ریشتر +اعلان +تک‌نفره +بلو +مناطقی +شافعی +می‌گفت +می‌خواند +ثانی +هست؟ +منو +لوث‌شدن +جنایت +برخاست +بوده‌است، +نمی‌باشد +اشراف +نداد +مهربان +الهیات +همه‌ی +زمين +کینگ +رول +والتوزیع، +مدرسهٔ +ترافیک +اتهامات +وای +بهنام +شجاع +سیار +ترسناک +ذات +مختار +عموما +اینتر +فرزندش +داروشناسی +ریسک +۱۹۹ +نیجریه +مظفر +حشرات +میدانید +جبل +آریزونا +نارنجی +کتابخانه‌های +میدانم +آرم +بشمار +اعتباری +کره‌ای +عکس‌ها +پیکچرز +تخته +متمایل +رفاه +شهبازی +میخائیل +تطبیق +نظریه‌های +بلوغ +عزیزم +۱۳۹۱ +محاسباتی +سنجی +مکانیسم +سریعتر +آبشاری +کالاهای +اشک +خانی +سازگاری +مارچ +گرین +قرص +خوانندهٔ +صفی +نازک +داروها +۳، +۱۳۶ +هماهنگ‌کنندهٔ +لینکلن +بانوی +خودروی +پل‌های +۱۳۳۸ +دیوارهای +ورامین +۱۴۵ +اتخاذ +کمیت +دارم، +مذاکرات +حول +برگزید +کارشناس +نامعتبر +سفرهای +رومیان +ربات‌ها +غیراینصورت +انیمه +به‌وسیله +استعمال +صریح +سازه‌ها +رامهرمز +اندیس +رازقنــدی +تثبیت +۱۰، +تصوير +گویش‌های +کتک +طالب +حماس +۱۳۲۹ +علیرغم +۱۴۸ +حزبی +استونی +اوین +غروب +حریف +استراتژیک +شگفت +مرگش +جانسون +پانزدهم +موشک‌های +گن‌آباد +ارتقا +باطل +خورشیدی، +آلفرد +ساموئل +بحرانی +قندهار +كردم +ماکس +گی +میخواستم +بچه‌های +۱۳۲۵ +شرطی +گشایش +زندگي +دایی +یون +فرانس +تورات +گزارشی +۲۲۰ +فیلم، +دهلی +مسافران +سنگر +نخواهم +موش +ریشهٔ +سخنگوی +زنگ +نینتندو +دیوانه +بمباران +مسئولین +استودیویی +شدیدا +تیلور +۱۲۰۰ +قزوینی +لاست +مسلما +ورق +شهرزاد +لطفی +کلات +بارداری +دیواره +باشگاهی +شکستن +تریلر +ممتاز +پرانتز +یوتیوب +بیهوده +ابدی +نباشد، +کیوان +طرح‌های +بدم +کاریکاتور +بدتر +داش +می‌رسید +میانجی +بيش +اختریان +سربیشه +روشنایی +تبیان +بکشد +اراده +چربی +خرما +سلطانی +شيخ +مقا +مستخدم +وب‌گاه‌ها، +نشینی +نرگس +۱۷۵ +تویسرکان +خاطره +برکنار +غیرقانونی +ساواک +نگاره‌ای +سین +شناسنامه +بناها +‌ها، +غرق +شعرهای +مسلط +سرش +اه +برکت +جنگل‌های +سلطه +اقیانوسیه +علما +بنفشه +یال +هولوکاست +دادستان +حلی +اجسام +غواصی +احاطه +والا +بیماریهای +صدوق +ریو +دیویس +ناهید +دهها +نتوانستم +ایکس‌باکس +ول +منبع‌ها +تاریخی، +٫ +کثیر +لیتوانی +شده‌ +بپرسم +قربانیان +جانشینی +سیریلیک +بوستون +یونانیان +دوبار +فرضیه +امروز، +دیده‌ام +عزيز +۱۴۲ +میگیرد +شلوارک۱ +مِنَ +ارسطو +ومبلی +بخواند +۱۹۰ +صوفی +صدق +کارب +گذاشتند +هزینه‌های +فردریک +نوشته‌اید +آو +عمده‌ای +م‍ +هیچگونه +حسی +اللَّهُ +معدود +مارکس +سنگاپور +رایانش +عادل +ریگان +میرسد +الگوریتم‌های +ائتلاف +فریدون‌کنار +بازگا +نگرش +هرحال +بدانیم +کفایت +فین +۱۳۲۷ +باورهای +بازگیر +لردگان +چرا؟ +تعویض +سلجوقی +جستار +نخواهند +می‌نمایند +دهستان‌ها +فرمانروای +خودتون +منتقدین +کلاردشت +اره +لزومی +مرتفع +ویر +سندرم +نیاید +آجر +دانشکده‌های +نمین +مق +تن‍ +اینچ +فوتسال +ساکنین +‍ه‍ +فرانسه، +صفحاتی +۱۹۰۲ +طالقانی +جعبهٔ +غارت +بزرگسالان +لین +۱۶۵ +قیاس +افغانی +نگذاشته‌اید +ساید +نادری +امامان +سنا +سرگذشت +رایش +توجیهتان +بروند +سمفونی +آهنگ‌ها +توس +تم +پنسیلوانیا +خرچنگ +مغان +سجاد +پایینی +تحریر +لوث +شانه +طوفان +اصولاً +کبودرآهنگ +تسمیه +عامیانه +بیشینه +فضاپیمای +بودایی +۱۸۹۰ +اقلیم +مثالی +جشنواره‌های +برایان +میرود +پین +آم +سرگرمی +مزایای +ریال +رسماً +ناحیه‌های +تازه‌ای +می‌دهیم +هارد +مقال +فراهان +دلیلش +میلیمتر +۱۸۰۰ +ماهنشان +سالار +جت +مردگان +فقیر +۱۵۵ +راستا +میکنیم +جوری +شلوارک۲ +پژوهشگاه +نیستند، +۱۴۶ +اینشتین +یخچال +روزمره +ارم +سنین +تحسین +سکه‌های +۱۳۱ +فحاشی +پاپ‌های +عینی +رسانده +رز +بودم، +ارزشی +ستان +باراک +اصلي +الکتریک +نامه‌های +عطار +علمي +بخشید +السلطنه +يعني +غلبه +مستقیماً +منش +رستاق +افراطی +بگیرم +سيد +۱۴۷ +ندارند، +الَّذِينَ +نمونهٔ +کریستال +قایق +نوادگان +سالیانه +می‌پذیرد +احترامات +شیری +سیاهکل +سرب +نصرالله +مانه +گیم +ببر +آستان +زیستگاه +ای، +داده‌ام +لوئی +شریعت +آموز +رتبهٔ +کمک‌های +نقدها +حلقه‌ها +ارتقای +هال +انسانها +پشتو +امیرحسین +سین‌آباد +رشید +۱۴۳ +شیرینی +مذاکره +تعدیل +کارمند +اعضاء +روانه +بنر +معروفترین +خیابان‌های +مشاوره +اکثرا +افت +کنگان +بگذارند +دامنه‌های +رحم +بیدار +تیپ +تنفس +افغانستان، +میشیگان +استعمار +فرخ +گذرگاه +توالی +تایم +جمله‌ای +ولادیمیر +دستوری +تساوی +ساختارهای +جانوری +قسم +۱۳۱۶ +هفده +یقین +صوفیان +می‌نویسند +رومرکز +بک +انگشته +مولف +نگفتم +یورش +ثبات +بیایند +بپرهیزید +وبا +اس‌جی‌اچ +جن +ورزش‌های +لامرد +سپیدان +کبک +عزت +افشین +کامرون +فیلم‌شناسی +پاول +نکنیم +درگیری‌های +رخداد +کیا +عرف +شازند +یکصد +استهبان +می‌گیرد، +نرسیده +ویژهٔ +ابتلا +اینطوری +گارد +بزن +مدتها +وعده +شرف +پيدا +نیدرزاکسن +زواری‌جان +اسدخانی +هندواروپایی +تصویرگر +مختص +استادی +هیپ +امشب +احیای +بنو +امامت +خونریزی +سیگار +کاسه +غرض +معتقدم +ساختم +صفح +روایتی +نمادهای +متوالی +خدایی +نمود، +عجم +آبهای +آمده‌اند +نموده‌اید +لاریجانی +شیوع +زمينه +الا +بیا +آزمایشگاهی +آنتن +قرآنی +بیستون +فاجعه +۱۵۸ +ریه +انعکاس +تقلب +هجدهم +طبرستان +تناقض +مدت‌ها +علمی، +تصنیف +فروغ +دایرةالمعارف +آلمریا +تاسیسات +گونهٔ +هیچکس +ایدز +آوا +۱۴۹ +مديريت +بیاد +پایگاه‌های +زیرصفحه‌های +مقاوم +گمشده +نشدید +نوزاد +سیف +دیفرانسیل +موافقان +بانه +فونت +صفا +واتیکان +اصالت +کتابخانهٔ +یگانه +کیت +ترجیحات +کنوانسیون +نانو +۱۵۳ +آنزیم +كردند +تیمی +۱۸۵ +هستید، +حوض +نویسنده، +ورد +حسنی +پديا +بویین +مادها +ناوگان +بنگاه +اردلان +صومعه +تورنتو +کارولینای +۵۰۰۰ +اشکالات +مسائلی +انداخته +نماند +دستمزد +بخواهم +سرقت +میدانی +ریتم +خوبیدگی +پوستی +اندی +الماس +بزنم +مقدونی +هسن +گروه‌ها +بروجن +تگ +منشی +ملکی +تبعیض +ببین +افق +خشن +کورین +دوی +قوام +ایلینوی +بچه‌ها +تکاملی +دخترش +برانگیز +اصطلاحی +مل +یکان +داراست +عرب‌ها +ناموفق +کبد +کوفی +رودها +پشته +رسالت +مرتکب +معروف‌ترین +نشوند +نبودم +بنیانگذاری +لیبرال +فرید +حوضه +ربع +نوح +سیاهه +تای +خستگی +پدری +برنامه‌ها +فرستادن +بیطرفی +نواب +نزول +استیشن +رادار +پخش‌کننده +سازند +عضلات +سعیدی +کوین +بنویسند +برم +بیایید +حجازی +شده؟ +تالیفات +حسینعلی +نیست؛ +مزاحم +فروشی +آموزان +میکرد +۲۴۰ +بحث، +وارنر +کوری +واکنش‌های +فستیوال +قارچ +لغت‌نامه +تاجیک +شرکتهای +هروی +ویژگیهای +عکسهای +چارلی +باشيد +داشتیم +بومیان +باقیمانده +یافت، +اشاره‌ای +فصلی +عبدی +بزرگوار +بیتی +مُعجَم +نازل +امپراتوران +مهمتر +کانی‌ها +۱۸۹۶ +محمدباقر +شایع +ادریس +که‌ +دهندگان +اعلامیه +به‌نظر +داروی +لیک +اتوماتیک +مي‌شود +فروغی +برآورده +بلا +آدولف +قشقایی +تنفسی +اردوگاه +زنجانی +تنه +گزیده +مریوان +پورنو +کامبوج +تل‌های +رمزنگاری +دامپزشکی +شاهنشاه +قرقیزستان +ارابه‌ران +نمودم +ضرر +بازنگری +دگرگون +بررسي +شده‌بود +ناپدید +متاسفم +نسخه‌ای +اشنویه +پیاپی +عبدالعزیز +۱۶۸ +اسباب +نسبیت +کعبه +مردم، +ذوب‌آهن +آنچنان +ادرار +رنسانس +سوسیال +دهخدا، +تختی +فاطمی +ماشین‌های +پاسکال +مینا +تابعی +سایتی +توانیم +ترين +توران +ادارهٔ +فهرست‌ها +خوشی +معینی +یادآور +مخالفین +دود +مدام +انی +تقاطع +پتاسیم +نساجی +ارد +اندیمشک +داده، +مخالفتی +دونفره +اندیشه‌های +علیزاده +آجری +برسیم +اقدامی +فقهی +اشکان +همبستگی +فرادیرینه‌سنگی +گناوه +کوفه +۱۸۹۹ +اینصورت +عبدالرحمن +لبه +بی‌پایان +میدهند +منشا +مرحلهٔ +بیطرف +کردید؟ +مسخره +مشخصه +عضلانی +اسارت +عنوانی +۱۵۲ +ندارم، +برچسب‌ها +اچ‌آی‌پی +منصوری +۲۱۰ +بینم +مجنون +تعاریف +تعهد +اقتباس +جلیل +می‌کنید؟ +رزن +مسئلهٔ +فرستنده +گان +قاب +کمونیسم +تناسب +ندای +توحید +هواشناسی +کرده‌اند، +منتها +روز، +شوال +لیزر +پس‌از +دزدان +دارد؛ +جنگ‌افزار +جایزه‌های +واحدی +تیموریان +ذكر +کنده +ترش +می‌خوانند +ریش +تمایز +پیشبرد +زندگانی +دلتا +پیش‌از +نقده +ایرلندی +هنرستان +قبال +فرصتی +دودویی +عليه +زیباترین +شاعری +سرما +ایلی‌نوی +شهبانو +پنالتی +بهاری +افتد +فیروزکوه +فایده +۱۶۳ +بروس +نیسان +نکردند +نمیتوان +۱۶۲ +روباه +سقراط +کشته‌شدگان +اورانیوم +عملا +طراحان +ماهیچه +سرم +اوهایو +علاقمند +نویسد +الجزیره +گذشته، +مزارع +گزینش +جنگهای +اطلاعی +نوشته‌ها +پارلمانی +۱۱، +جنابعالی +اسفندیار +امیدوار +ک‌گ +گازهای +کبود +زمین، +تلگراف +لئونیداس +گرمای +کتابخانه‌ها +آشوری +طعم +راد +زنانه +عربی، +جادو +حمیدرضا +جنگ، +جابجا +ماکیان +بیابید +شکاف +گلزار +متفقین +متاخر +سایتهای +بایگانی‌ها +بهره‌برداری +جنایی +کارون +شهدای +میامی +پدیده‌های +هستم، +برکلی +نایین +ببینند +استانداری +۱۶۱ +پسری +شوالیه +کت +شاخه‌ای +مقاطع +آنوقت +اسکو +۱۸۹۲ +نده +رسانید +۲۳۰ +تاسف +هايي +پلدختر +تاجیکی +جاجرم +وضع‌کننده +استر +همنشین +زحمتی +کانادایی +تبلیغات، +زهک +دولت‌های +ترمودینامیک +سوری +خلفای +درآن +فراگیری +ختنه +امیرآباد +تروث +بوم +زاد +خنج +بروم +سومالی +جیم +دیجیتالی +عفو +سوشی +اصفهان، +بلاندی +کوچک‌تر +گمنام +سکوی +نزاع +احتیاط +گردید، +بزنند +علنی +ویلا +۱۳۲۶ +الهه +هدر +ظلم +ناو +می‌کردند، +الحکمة، +یاقوت +حتي +شرکت‌ها +تعلیق +خواستند +کاروان‌سرا +نکتهٔ +رشته‌ای +باهم +بپردازند +درجات +وجودی +بودا +نیوتن +منطبق +نصرت +ال‌جی +سومی +فلش +۱۳۸۵جمعیت +فریم +دوما +ساقه +اسماعیلی +دینامیک +المقحفی، +المُدُن +فیلم‌هایی +فیزیکدان +محضر +آخوند +فراهانی +صید +بسا +الیَمَنِیَة +بنایی +۱۷۳ +می‌گوییم +درآمده +مورخان +یونیکس +جاها +وام +کوتوله +۱۷۶ +ژرفای +موجودی +مرادی +بدنیا +پمپ +پرستاری +می‌شوید +مناره +انقلاب، +برجستهٔ +جذاب +نوشتارها +نمیشه +مایک +امیری +چناران +ــ +گردو +تفویض +دخیل +۱۵۹ +بنیادین +بدیع +سالیان +مواضع +وَالقَبائِل +۱۶۹ +می‌بیند +درگذشتهٔ +داشته، +قنطورس +۱۸۹۸ +تصمیم‌گیری +مشمول +رودان +فراگیر +آمده، +نفهمیدم +۱۸۸۹ +شده‌اید +نفی +افسردگی +می‌دانستند +آلات +قوت +دانه‌های +محمدحسن +عزيزی +جامی +نجم +طرحی +گاندی +جنوبی، +بصره +اروگوئه +شرکت‌ها، +پورت +خجسته +زمانیکه +ریشه‌های +فمینیسم +گاردین +بایست +وار +دیوان‌سالار +فوتبالیست +۱۶۷ +آلمان، +شعله +آناتولی +على +شمالی، +سیمون +ظروف +رستوران +دایر +می‌گذارند +تفاهم +آناتومی +گذراندن +شكل +مرگ‌ها +آهنگسازی +لیتر +دزدی +فرموده +معصوم +اطاعت +تارنمای +فارس، +پلان +هانس +فریدریش +ملی، +روحانیت +اوّل +نتيجه +وادار +صورت، +۱۳۰۴ +ترتیبی +مبارکه +بنیان‌گذار +۱۷۹ +ژوزف +اردستان +افزودم +مطبوعاتی +ارز +جنجالی +نوازندگی +سوزان +دارن +افتادن +هایشان +تحقیقی +سهند +سپاسگذارم +فیزیوتراپی +محافظ +ماشینی +ربر +یدالله +میمون +سیاستهای +نگارهٔ +چه؟ +صراحت +رسته +تجویز +توفیق +مغولستان +کین +وال +ساکورا +پیشروی +متوفی +تازی +دیلم +پل‌دختر +می‌خواست +صدیق +نمی‌بینم +ایلات +درحالی +غلات +نوه +هاله +سیستمهای +کتیبه‌های +سیال +منبر +بیک +۱۳۱۴ +۱۳۱۸ +حسين +۱۷۱ +درشت +سوق +برنامه‌ای +گهواره +دست‌آوردهای +تعبیه +رادیوی +ساسان +درامز +۱۲۹۹ +تجسمی +سیمان +گنجی +کشش +اسلوونی +ویلسون +داماش +إِنَّ +کارتوگرافی +کاشت +دستان +لید +نوازندهٔ +نمی‌شد +قران +ایدئولوژی +کامپکت +ناغان +قرائت +کاراکتر +خانه‌ها +شفاهی +فله‌ای +شهرسازی +اعتصاب +۱۸۱ +ویدیو +شايد +ویرایشگر +پردازد +داده‌اید +حاد +اجتهاد +مرطوب +کلماتی +مهریز +حلال +بیافزایید، +۱۵۷ +همجنس‌گرایان +لینکی +تطابق +باورند +دالاس +إِلَّا +اصولی +کپی‌رایت +الفبا +کیهانی +تاب +شرعی +محتوی +هانری +می‌دهند، +یوگسلاوی +بگذارم +تداوم +گریز +نشده‌اند +شناخته‌شده +انعطاف +اندک، +دعوا +کری +تبیین +احساسی +ساعات +معاصر، +پیشوند +طبع +میاندوآب +اخترفیزیک +مطمئنا +پرسید +انگل +برکناری +رولینگ +حفاری +زیارتگاه +منتسب +پیام‌های +گسسته +طريق +باخ +۱۳۲۳ +کلیساهای +معصومه +شهروز +متناوب +۱۸۹۵ +پن +ابراهيم +۱۳۱۳ +بطوریکه +رابین +آموخته +میدان‌های +تاریخ‌نگاران +بکر +میش +پخته +قلمداد +رویا +باشید، +سیستانی +قومیت +جرمی +لوس +آفرین +تلف +خوارزمی +محتوایی +سول +دبط +جُستارهای +می‌نمود +روزنامه‌ها +یت +دگر +بانکی +سدان +متغیرهای +یابند +بکارگیری +انتاریو +کوسه +۱۶۴ +بلخی +بیم +خلخال +حائری +۱۸۹۳ +آورده‌اند +نقطه‌ای +علمجو +استیل +سلولهای +گوگرد +میتوانند +گوارش +سبزی +۱۶۰۰ +جوراب۲ +زیرین +ميشود +پنبه +آورد، +حرفهای +لنگرود +فریمان +سلاح‌های +میانگین‌جریان +غبار +مردانه +مؤسسهٔ +اسراییل +تک‌نواز +۱۶۶ +لکی +خبرنگاران +پالایشگاه +مصلحت +۱۷۷ +مجروح +پرستش +دوگانه +مدفون +ولیعهد +سرزمینی +آق‌قلا +اساسا +بهر +ملي +كنار +روستاي +کلاس‌های +سفره +نرمال +وری +کیف +۱۸۸۰ +۱۹۸ +زدید +زراعت +رهنمودها +توضيح +۱۷۲ +۱۹۲ +پدیدار +وایت +بمانند +لرد +دستم +ایسلند +لیقوان +نیافتم +باتشکر +تئودور +عبادت +تبديل +نکردید +مسلحانه +دیزنی +رانش +فرهنگ‌های +مخاطبان +دول +کتابت +سلیم +ایرانی‌تبار +غلظت +شونده +۱۲، +اوراق +سامانی +اقتصادی، +۲۵۰۰ +شخصیت‌ها +فحش +سربازی +هشداردهنده +ندرت +۳۲۰ +می‌شه +۱۸۹۷ +فروهر +صلی +سیوند +انجمن‌های +بعلاوه +ترشح +فرج +جاي +بخیر +محراب +کارتان +هجده +قریه +ربیع‌الاول +ضخامت +بارندگی +بح +نسیم +زهره +جادویی +تالاب +جنون +بروی +۱۳، +فیلد +کریسمس +میزبانی +می‌کنید، +آپلود +برگزیدگان +یش +خانواده‌اش +کریستوفر +بیننده +توکلی +می‌سازند +لنگ +تداخل +مقدمات +۱۸۹۴ +الوند +مع +گناباد +مزدا +رکن +عیلام +ترقی +منکر +معامله +اینچنین +کول +سازمان‌ها +مأموریت +موعود +دولت‌آباد +بلبل +طولی +می‌رسند +اجاق‌کندی +ديگري +ندارد؟ +براین +مصور +اعتقادی +فرخزاد +درباره‌ی +خداآفرین +گفتاری +خوانی +پارامترهای +تهاجم +آیوی +توضیحاتی +بشرویه +۹۷۸ +کیست +نداشت، +شهروندی +برخي +۱۵۶ +سمرقند +نوا +كمك +لامپ +عماد +رام +اينکه +ضمیمه +بنابراین، +تصویربرداری +سیبری +یوفا +کلر +گوجه +حیف +سواری +۱۳۱۲ +طارم +۲۶۰ +اباد +عنوان‌های +مركز +مقوله +گوستاو +مرعشی +بحر +تون +انصار +جداسازی +تصفیه +سازندگان +ببنید +محافل +نقره‌ای +تیرماه +پیاز +سرسبز +انه +چشمان +تایباد +اشیا +طرد +گوهر +نکن +هرزگوین +اقلید +خاص، +ثالث +علی‌رضا +آنگونه +مستمر +عضوی +هامبورگ +پورتال +تویوتا +رامیان +هخامنش +اردل +قاطع +گنجینه +روشنفکران +تصادف +۱۹۷ +جزیی +مؤسس +روبروی +آلاسکا +خوشه‌مهر +آرد +صالحی +سونامی +کشیش +پروس +انحصاری +کاسته +دوستانش +گاوران +دلالت +۱۸۴ +اصحاب +جزیره‌ها +مهدوی +آبیک +افزايش +مزیت +جوابی +صغیر +منحنی +رمین +سانتیگراد +دبیرکل +غریب‌دوست +بنزین +اپیزود +استانهای +بهاءالله +سپید +کمونیستی +سوگند +شهباز +اکتشاف +استحکام +مفاد +بسازد +اسکناس +۱۴۰۰ +مبدأ +بخورد +مناظر +زا +پرستی +تمبکا +محرمانه +سکنه +زیتون +رومانیایی +جسارت +عمومی، +دات +آهنی +بینید +مخابراتی +نظرش +مولداوی +العظمی +ولف +ممکنه +راننده +اولاً +وَمَا +وسیله‌ای +موی +بادلو +چرب +مسافت +مکس +۱۷۸ +پودر +عوام +که، +پنجم، +گرگوری +میسر +مفصلی +استبداد +حیدرآباد +آلیس +فیروزه +ریخت +اینان +کروی +وقف +شعارهای +۱۹۶ +سملقان +فروخته +۱۷۴ +نبوده‌است +دیکتاتوری +میدهم +ظریف +معتبرترین +سیاسر +ایرادات +اجماعی +۱۹۳ +منحل +زاید +میخواهم +صاحبان +مهلت +می‌پرداخت +ماهه +جری +بازرس +وَلَا +گلشن +برهنه +نوشته‌ام +می‌شود؟ +صخره +عمو +ابد +بیداری +۱۸۸۸ +۲۷۰ +بعلت +پنیر +حاتمی +خانقاه +رس +شکسپیر +معذرت +پايان +ساختگی +آموختن +فقدان +پاسخگویی +زانو +كوه +لزوما +قمر +شهریاری +بيان +واین +صورتیکه +بدنبال +پاره‌ای +ارمغان +می‌شود؛ +شغلی +دیگ +عنبرآباد +امریکایی +پیشرو +تجربیات +علوم، +پیری‌کندی +ازجمله +به‌نام +صومای +۳۳۰ +۲۶، +اسطوره‌های +منفجره +دستتان +رشته‌کوه +۱۹۵ +برن +بلده +شیعی +رحیمی +رجایی +کجور +۱۵، +تاون +آموزگار +آستارا +هیل +ترانه‌ها +یوری +کلاله +محو +خوانندگی +زار +عیب +افسانه‌های +پخت +نامبرده +پنجشنبه +سور +نروژی +تکنیک‌های +دریاچه‌های +مالدیو +سوسن +کیسه +کاوش +دابودشت +کردن، +زندگان +مقدمه‌ای +موزهٔ +۱۸۸ +برپایی +داگلاس +فضل‌الله +زینب +اللَّهَ +صحرایی +کرت +اذیت +نمی‌رسد +آتشفشان +۱۳۲۱ +بلاروس +انگ +ارگان +بسامد +نشوید +بزرگای +کلارک +۲۱، +بشدت +نقوش +خوشنویس +الفبایی +نخ +رفیق +ناراحتی +رسی +بخواهند +طرفداری +دردسر +۴۵۰ +۱۸۳ +ایرباس +پرت +فرآیندهای +گردشگران +مخرب +میگم +کارتون +نوژن +سفری +صندلی +می‌کرده +نزنید +ج۱ +میخواهید +گنگ +می‌ریزد +پشتکوه +ویکی‌پدیاست +دلاری +ویکیفا +خيلي +بازگشایی +چشمگیری +نیتروژن +بافی +لانه +بدید +آشتیانی +باشد؛ +محققین +۲۴، +یوتا +طرفه +توسعهٔ +کشتی‌های +۲۰۶ +جاستین +شوشتری +اسمیت‌سونیان +طوطی +عباسیان +رده‌ای +زرند +می‌رود، +ابتکار +دهلران +بستان +برجای +۳۸۰ +رمانتیک +ترجمه‌های +کاربرها +بندری +پرداختن +منهتن +پاتریک +طناب +چهارم، +نتواند +بور +دانسته‌های +روحیه +میلاد، +برزنجیر +مرجان +دهند، +شهرستان‌ها +سپرد +داران +استوارت +دوچرخه +طراحي +۱۱۰۰ +خانه‌ای +نوآوری +نامنظم +کامپیوترهای +دیوانسالاری +وفادار +هرودوت +امسال +استثنا +فرانکفورت +مجالس +خدمتتان +کتابداری +لاین +پوران +آنالوگ +برادوست +۲۰۸ +شادباش +می‌شناسند +بولکیمده +می‌نویسم +چالدران +کهنوج +تطبیقی +۱۶، +دیدگاهی +منحرف +شنوایی +تیز +تیغ +موشکی +پرشیانا +امیل +ایزدان +سه‌گانه +پنجه +۱۸۹۱ +۱۳۲۲ +دين +قبله +جهنم +خدماتی +ببرند +مأمور +نیستیم +کلمه‌ای +اعتیاد +فرانکلین +معجزه +ذهنم +بازماندگان +مصوبه +کلینتون +برسند +معاهده +نمیکنم +چندگانه +شهرستانی +لاک +موضوعاتی +خوسف +اسک +خروس +لتونی +وات +کرد؛ +رودکی +خدمتم +تاری +مجلسی +فهمید +هفتگی +کروز +برگرداننده +قیصر +معروفی +فكر +نو، +فضانورد +فتح‌آباد +هورمون +الفاظ +آمازون +بیاوریم +دستهٔ +می‌کردید +بینایی +پافشاری +بردم +دیپلماتیک +سنگینی +ض +نمره +غیرآزاد +فریب +پذیرد +حیطه +اصلی، +تربیتی +محال +ارجمند +می‌یابند +فلج +اربر +اینجا، +آوای +دودانگه +چاه‌بهار +همزه +۲۳۸ +تمبر +انوشیروان +متن‌های +پشتوانه +عجب‌شیر +قسمت‌ها +آشوب +بدرود +نظرشان +ه‌های +روزتان +استفان +گیتاریست +نشده، +دینار +چاره +تیموری +زهی +مغولی +۲۵۶ +هیوستون +الموت +۱۸۷۹ +راگبی +لوکزامبورگ +حیث +عاج +سخت‌افزار +رمانی +نگهبانی +پتروشیمی +چادر +صلیبی +کنکور +کانسار +بلوچ +زاهدی +هستید؟ +دوبله +طیفی +نشریه‌های +زنبور +حزب‌الله +اخوان +اجزاء +ژنو +دعای +مزمن +سخنی +نهایتاً +اندرو +میشوم +۱۸، +دارمشترانگ +می‌دارند +سه‌شنبه +حفره +زرندیه +ذخایر +۱۳۱۹ +زنجیر +سبکی +قیمتی +جنیفر +۲۰، +تعمید +آبگرم +حکمرانی +پلاستیک +بی‌نزاکتی +تماشاگر +لایحه +بازه +تحکیم +موضعی +جویی +محافظة +شاه، +ما، +۳۰، +آمبرلا +کلرادو +هیجانی +مجتهد +گیاه‌شناسی +اضطراب +جنگ‌افزارهای +۱۹، +ادوار +مسیری +چمران +پایه‌های +گیتاشناسی، +نمی‌کنید +گیل +متین +آدلر +۱۷، +بعدش +باکس +یاس +حکمیت +کیلوبایت +بریده +هموار +معقول +کروم +۱۸۸۶ +غزنوی +نوش +بازنشستگی +گوینده +یک‌نمونه +هنر، +میاد +عظمت +جهش +جانبداری +شبكه +آسا +استاندار +۲۰۹ +فرانسیسکو +بریتنی +محدودیت‌های +بشکه +بنگرید +تاثیرات +آسفالت +گیج +کاروان‌سراهای +فراموشی +گلدار +ترتیب، +يافت +همینجا +بدخشان +۲۵، +تمدید +زيادي +هستش +رضا۱۶۱۵ +بودی +مهرماه +اسکندریه +لزوماً +سیستمی +هارون +نگفته +می‌دانیم +سایوز +آن‌را +نوزده +بمبئی +فان +میدانند +۱۸۷ +دانستند +اجاره +فورت +مراقب +نفرت +نوی +۲۰۴ +تدریجی +تهی +نورآباد +گزاره +کلامی +نتیجه‌ای +پانک +هاكل +عفونی +بسر +پیشگامان +بلاغ +زئوس +بريفين +گزارش‌های +نمایندهٔ +سیالات +۱۸۲ +فارسان +جلدی +فلک +تحقیر +فهمیدم +ناتو +سایرین +شناور +انستیتو +نیکو +مارکسیسم +تبعیت +تفریح +زبان، +گلوگاه +بقیهٔ +کمپین +احراز +بودن، +محکومیت +کماکان +بستری +تروریست +سرواژهٔ +دانمارکی +آمستردام +همی +داوید +کافیست +دنی +رون +۶۰۰۰ +لابد +کانتری +سس +کسری +می‌فرمایید +سیاستمدار +حریم +معنویت +عسکری +بخشیدن +محصور +مدافعان +گرایش‌های +واگن +حجر +سرداران +مشهود +یافتم +تنسی +نهر +دارالفنون +نمايش +بسياري +سابقهٔ +یتیم +توپولوژی +۱۴، +نگارشی +جمعيت +تنبیه +کیو +سقط +شریفی +کما +میکروبیولوژی +دیابت +تاتنهام +منقرض +تاتی +محمددین +انگليسي +فارسی‌سازی +زمینهای +شهدا +۰۸، +متکی +کوه‌ها +دزد +کنایه +مشایخ +ارزان +ماسه +هرمان +تنظیمات +اونجا +خار +هیلاری +چنار +خزانه +شکاری +عجایب +رنو +قراردادن +جابر +سروستان +مستطیل +مجموعه‌ها +بهمیی +یکسال +سرخرگ +نادرشاه +لیاقت +دوستار +وارده +کاستیا +لرزه +اى +بجا +نم +مغولان +امارت +کشاورزان +طبی +کجاست؟ +نبح +نمایم +للطباعة +بکنند +داستان‌ها +آمیخته +تاريخي +اندازه‌ای +پیکار +مستعمره +کوهپایه +تصدیق +۱۳۱۵ +فیلترینگ +۰۹، +آدینه +توبه +بصری +بکنیم +هوتک +فیلم‌نامه +پشتون +زمره +حبیبی +اسکندری +نیایش +هائی +رقابت‌های +داوطلب +ازش +بنظرم +دلیجان +رضی +مصاحب +پرون +بازگو +آگهی +قولی +سیسیل +انگلیسی‌ها +مکاتب +حبیب‌الله +سانسکریت +توکل‌آباد +نموده‌اند +حیوانی +پروژه‌ها +گیتی +فالتز +سنگسار +بخت +میلانی +مارکوس +نید +شدیم +۲۲۴ +مش +فصول +کتابش +می‌خواهیم +مشی +آنی +مادهٔ +میکردند +یکا +طلبان +عهدنامه +الملل +ارکان +کاربریتان +جلال‌الدین +ایرونی +یونس +آبراهام +فرشتگان +فارسی‌زبانان +۲۰۳ +۳۵، +ناتمام +موظف +ایت +می‌زنم +ییلاق +منی +كم +گریه +بسازیم +سیبک +انجا +موفق‌ترین +۱۳۰۷ +ثروتمند +گریخت +زمان‌دار +تروا +ژرمنی +برنارد +تشكر +ژنریک +راهبردی +گره‌های +پارسی‌گوی +بندهای +مبادله +اسفندیاری +سرتیپ +خوارزم +کلاغ +ياد +ايراني +نجف‌آباد +سولفات +كامل +ناظری +شهرستانهای +أَنْ +میگ +پادگان +مرتضوی +زياد +کلود +مقاصد +بهارستان +دیکتاتور +باستان، +۳۱، +اسکای +الکلی +میباشند +پارتی +بیاورند +لایه‌های +پرتقال +آمیزی +۴۰، +۱۸۶ +رستاخیز +خرگوش +فیبر +لیبرالیسم +مخترع +ۗ +تعمیم +برمی‌گردد +تل‌آویو +خورش +مولد +ستم +باغات +نژادهای +ضربات +آنست +ارواح +جوار +اپرای +تحتانی +آنتوان +زحمتش +۱۸۸۲ +بازگشتی +رفت، +۱۸۹ +هوگو +گیلاس +۲۰۵ +دستاوردهای +قضائیه +۴۰۰۰ +مستقلی +رعنا +بخوان +۵۶، +سوزی +تلاشی +هرکسی +میلی‌متر +هفته‌نامه +برومند +کباب +سرمایه‌گذاری +پلاتین +دنیس +وگاس +قرآن، +نصرت‌آباد +۲۲۵ +۱۹۱ +بافق +ژاله +آبریز +صدد +املاک +مقاله‌ +بوانات +پژو +زمان‌ها +کامیاران +پگاه +۲۰۲ +حرف‌های +ترغیب +حک +مسطح +دی‌وی‌دی +جانبه +سفیران +غدد +هستند؟ +مدرسه‌های +۵۲، +منبع‌دار +چاله +نائین +مدير +عکاسان +آب‌خورده +فیات +خبرنامه +مشهدی +استرالیایی +سیامک +بگیر +شایان +درسته +نامند +ویرایشهای +گل‌ها +مایا +گروه، +آتشفشانی +کرده‌است، +نیمهٔ +آزادشهر +رانده +علاقه‌ای +ثریا +متشکر +ولت +فرزانه +صورت‌های +دانشگاههای +وز +ویدئوی +جنازه +برتون +جلوه‌های +تغییرمسیرهای +بیانیه‌ای +دون +نبوی +یک‌بار +رک +حزب‌های +مدارهای +میگویم +كنيم +معلق +تماشاگران +نش +نصیر +۱۹۴ +رضاخان +گردد، +کنسول‌های +قسمتهای +شورشیان +دقیق‌تر +مداخله +علاءالدین +استنباط +مصرفی +باردار +اهورامزدا +ادبيات +باهنر +مقرر +عزاداری +كلمه +خونین +محدودی +نمی‌دارد +ذوق +پرسش‌های +بریم +قشر +۳۸، +صالح‌آباد +محسنی +تخلص +شکل‌های +شوی +رنگ‌ها +توربین +مگابایت +فسفات +واجد +اهانت +محفل +برحسب +گیگا +گيرد +۱۸۷۰ +صنفی +تن‌تن +برگردانده +دایناسور +لای +می‌بینیم +۰۴، +فرمائید +سیارات +۵۱، +تص +سرودهای +معترض +ممكن +متا +می‌شویم +ثلاث +گفته‌های +بی‌طرفانه +هاپ +نهان +ادارات +عجیبی +جنایات +دستورالعمل +پارا +نهادند +ام، +فتنه +فواصل +۱۸۵۰ +توریستی +مرمر +دیتابیس +۴۲، +کلیات +۱۸۸۳ +لنین +بلكه +کاتوزیان +میسیسیپی +معاویه +یوونتوس +کشاورزی، +هوافضا +كوخرد +فاریاب +محيط +نکنید، +میترا +رنگین +آلپ +آلومینیوم +ملودی +سیاستمداران +گمر +اسکان +مختصری +قشون +جوادی +رباتی +۲۱۱ +جایز +۲۷، +محمودی +كاربران +یافته‌اند +بگذریم +محوری +زمان‌های +۲۲، +انصراف +میلا +ساير +۲۱۴ +تصریح +۳۶، +۲۸، +آلباسته +وظیفهٔ +آذرشهر +خدمه +بارانی +فیزیک‌دانان +۱۸۸۴ +تماشای +۱۳۱۱ +نويسنده +علامرودشت +افزاری +گلشیری +عملیات‌های +داس +ناخواسته +هوتن +واسه +ثانیا +لینه +سنج +اروپا، +ایلیا +بازمانده +بشریت +شناسی، +۱۷۰۰ +کالیفرنیا، +نکرده‌ام +سیلیکات +آزاده +کامنت +یونیکد +آمدم +احضار +توده‌ای +فرایندهای +بیماری‌ها +آخه +تبلور +۰۷، +۲۰۷ +مونوبوک +تصمیمات +اختراعات +جشنوارهٔ +مشاهدات +ریزشگاه‌ها +۲۹، +فیلادلفیا +یزید +سکولار +خشایارشا +سنتور +محافظه +کاپ +نادرستی +علی، +محیط‌های +منفرد +اهتمام +القاعده +علاقهٔ +لرزش +عصبانی +پسند +لیل +۲۲۶ +جدای +جواهر +ژولیوسی +کوچک، +شمیرانات +بخوانند +ربیع‌الثانی +۵۰، +۲۳۵ +توپخانه +نیکلاس +ویستا +فردیناند +۲۸۰ +تشییع +نمیکند +موسیقی، +نیرومند +۱۸۷۸ +غفاری +بفتا +هویدا +صدیقی +سلیمانی +سياسي +شهرضا +جوانرود +انتشاراتی +شخصه +۵۵، +آسیاب‌های +خوب، +راههای +والنشر +حماسی +عکسها +۲۱۲ +۱۸۸۵ +تعریفی +قاسمی +مصادف +مفرغ +گشتاور +۱۸۷۵ +شکل‌گیری +طهماسب +موجودیت +ستاره‌ها +آوردید +سازه‌های +۲۱۷ +ببریم +ارسنجان +بیدگل +مگه +عبادی +فایل‌های +۱۸۷۶ +تبریز، +رهنما +سپر +قاره‌ای +وو +جعبه‌ای +دانش‌نامه +اجتماعي +هیجان +کارتر +نرسید +۳۳، +کارم +نمی‌شود، +نسل‌کشی +نمونه، +صمد +دریک +میله +پلاسما +زاغ‌ده +داروین +۴۴، +ویس +قاچاق +املای +نامیدن +گنجانده +شادگان +نی‌بید +۲۲۲ +تسهیل +هلن +ناپدیدشدن +خط‌ها +ابلاغ +شمع +بازی، +فندقاع +جوهر +پترزبورگ +هخ +سکو +۴۱، +یاسر +۵۷، +مستلزم +آلبومی +کلک +ضخیم +پاشا +۲۳، +۱۸۸۱ +دی‌ان‌ای +حساب‌های +غلامعلی +خواندند +معلمان +همیلتون +مداری +مست +تصویرها +اندیشهٔ +شدیداً +دیواندره +کنن +بشوند +نیامد +مانگا +۱۳۱۷ +چسب +شجاعت +مشتاق +ایرا +دانا +بریتیش +ویکی‌پدیاها +مهم‌تر +روبرت +کافه +ئی +ارضی +دست‌کم +دندان‌پزشکی +مهرآباد +كننده +رضوانشهر +پراگ +پال +فرسایش +درگاه‌ها +راور +میکروسکوپ +فشارهای +آرزومندم +مصاحبه‌ای +ویولن +دریافت‌کنندگان +نجیب +سئول diff --git a/libs/harfbuzz/perf/texts/hi-words.txt b/libs/harfbuzz/perf/texts/hi-words.txt new file mode 100644 index 000000000..1dc18dcc1 --- /dev/null +++ b/libs/harfbuzz/perf/texts/hi-words.txt @@ -0,0 +1,10000 @@ +के +में +की +है +का +और +से +को +है। +एक +पर +श्रेणी +वार्ता +भारत +हैं +भी +यह +शीर्षक +पूर्व +लिए +गाँव +ईसा +उत्तराखण्ड +किया +ने +इस +संवत +कि +हिन्दी +जो +। +जाता +गया +या +जिले +वर्ष +जिला +नहीं +कर +साँचा +ही +हैं। +करने +हो +रूप +था +साथ +द्वारा +जन्म +तहसील +फ़िल्म +होता +तथा +बाद +विकिपीडिया +आधार +अन्य +प्राचीन +कुछ +सदस्य +अपने +इसके +प्रदेश +तो +एवं +तक +चित्र +बाहरी +राज्य +जा +प्रकार +सरकार +नाम +दिया +होती +स्वागत +कई +वह +बिहार +करते +सप्तर्षि +जैसे +थे +समय +अनुसार +आदि +वे +सकते +अधिक +वाले +किसी +आधिकारिक +सकता +कड़ियाँ +भारतीय +उत्तर +मण्डल +हुए +न +जाती +प्रखण्ड +हुआ +क्षेत्र +लेख +द +बनी +होने +उसके +करता +इन +अंग्रेज़ी +संदर्भ +थी +था। +शक +कारण +भाषा +बहुत +स्थित +पहले +उनके +प्रसिद्ध +सहायता +जब +दो +अपनी +कोई +सबसे +अलावा +स्थान +होते +कम +विश्व +लिये +ये +जाने +बारे +लेकिन +प्रयोग +उन्होंने +राष्ट्रीय +वर्षों +कहा +पृष्ठ +गए +रहा +आप +देखें +व +एक्स्प्रेस +तरह +मे +करना +शामिल +सभी +प्रमुख +आंध्र +इसी +अमेरिका +प्राप्त +करें +अन्तर्गत +इसे +माना +सितंबर +उस +५७ +इसका +जानकारी +नगर +मुख्य +हुई +शिक्षा +उन्हें +संस्कृत +कलियुग +बीच +गई +विक्रमी +रहे +उपयोग +मार्च +पोर्टल +काम +वेबसाइट +जनवरी +कुमाऊँ +उसे +शहर +जाते +उनकी +लोग +जिसमें +देश +दी +संघ +थे। +भाग +लोगों +जीवन +१ +कार्य +जी +फिल्म +विशेष +बार +ओर +२ +इतिहास +कभी +दोनों +अब +निर्माण +२००९ +पुरस्कार +वाली +शब्द +पताका +अधिकांश +चिह्न +विकास +धर्म +केवल +लिया +ए +दक्षिण +पुराने +जुलाई +यहाँ +नया +स्टेशन +फिर +लगभग +संयुक्त +अलग +आन्ध्रप्रदेश +गढ़वाल +स्थल +दिल्ली +ई +आरम्भ +अपना +जून +विस्तृत +यदि +प्रान्त +इसकी +सूत्र +शुरु +मंदिर +जालपृष्ठ +जिसे +घटनाएँ +कृषि +दौरान +करती +निधन +दिन +संगीत +यहां +तीन +क्योंकि +इसमें +साहित्य +ऑफ़ +मूल +भूगोल +॥ +पास +पटना +नए +हालांकि +सिंह +प्रदर्शित +प्रतिरूप +अप्रैल +बात +विषय +टेनिस +२०१० +प्रतियोगिता +प्रचलित +कहते +विज्ञान +विभिन्न +अगस्त +ऑफ +पद्धति +छत्तीसगढ़ +सन् +जाना +शुरू +बना +समूह +अनेक +थी। +ता +प्रामाणिक +मध्य +रही +सूची +संख्या +व्यक्ति +ऐसा +गणना +प्रति +आज +तब +उनका +क +इलाहाबाद +ऐसे +मैं +काल +हम +युद्ध +गया। +वाला +श्री +आदर्श +स्थिति +सी +सकती +दिसंबर +प्रदान +विक्रम +विश्वविद्यालय +रेलवे +बड़े +सामूहिक +किया। +किए +राज्यक्षेत्र +यातायात +उन +चार +उपरोक्त +दर्शाता +बन +अर्थ +अलीगढ़ +दूसरे +तौर +गयी +५८ +अन्तर +उत्तरा +राजा +प्रभा +क्या +घटित +मानकर +विभाग +कैलेंडर +देने +बनाने +खेल +प्रथम +हिंदी +इन्हें +एकल +उसकी +एंड +मसीह +अथवा +अमेरिकी +जहां +उदाहरण +कलाकार +निकाले +आवश्यक +७८ +महत्वपूर्ण +पुरुष +मई +नदी +जिसके +प्रभाव +आम +जूलियन +योगदान +किये +अधारित +ले +अधार +इस्तेमाल +सेवा +३०७६ +जिसका +३१०२ +पंचाग +६६७६ +चर्चा +भोजपुरी +कैसे +उर्दु +कलेण्डर +करके +चाहिए +स +कला +उपलब्ध +जनसांख्यिकी +साल +काफी +फर्रुखाबाद +आगरा +कंपनी +३ +उच्च +अक्तूबर +आ +मेरा +स्तर +नवंबर +नीचे +देता +अध्ययन +जारी +कोड +पहली +प्रणाली +अगर +ओपन +ध्यान +उसका +नामक +बड़ी +जल +नैनीताल +अक्सर +अंग्रेजी +सरकारी +वर्तमान +रंग +जिससे +मेल +पुलिस +रखा +प्रत्येक +हर +बनाया +ट्रेन +सामान्य +दुनिया +भूमिका +लिंक +दे +जबकि +सन्देश +शरीर +पता +भागलपुर +विचार +जहाँ +लगा +लेकर +बड़ा +वर्ग +आगे +छोटे +तथ्य +समाज +पानी +इससे +उसने +देशों +महिला +इसलिए +देना +पर्यटन +एस +परिणाम +अल्मोड़ा +सब +स्थापना +बाह्य +स्थापित +पौड़ी +दल +माध्यम +आधारित +पश्चिम +प्रदर्शन +सर्वश्रेष्ठ +चीन +शक्ति +बाहर +बी +ऊपर +बेगूसराय +उत्पन्न +हेतु +डी +आशीष +अतिरिक्त +समान +वीं +हिन्दू +गये +परिवर्तन +आधुनिक +लिखा +कुमार +देखा +अंत +मार्ग +मानव +रेल +अक्टूबर +आपको +घर +प्रश्न +दूर +कन्नौज +भटनागर +सामाजिक +प्रकाशित +अभिनेता +देते +कुल +अभी +जिस +होना +आई +४ +पूरी +संबंधित +रहता +ज्ञान +ब्रिटिश +कृपया +हस्ताक्षर +व्यक्तिगत +बिना +नई +रोग +१० +दशक +अधिकार +परिवार +शैली +लेखक +संस्करण +जिनमें +सेना +संबंधी +औरंगाबाद +प्रक्रिया +यात्रा +२००८ +नये +आवश्यकता +ऐसी +स्वयं +होगा +संबंध +चिकित्सा +मात्रा +परियोजना +प्रबंधक +१५ +विकसित +संदेशों +होकर +प्रकाश +पहाड़ी +पहला +आकार +सुधार +जगह +पन्ना +सही +मैथिली +तैयार +नवम्बर +पिता +मुक्त +क्षेत्रों +रचना +१२ +२००७ +पूरा +पी +संस्थान +५ +लोक +१३ +चरित्र +तुलना +हुआ। +लाल +उत्पादन +जनसंख्या +रहते +उसी +इनके +ा +१४ +संदेश +ज्यादा +शताब्दी +मृत्यु +साधारण +पाकिस्तान +मास्टर्स +दूसरी +पुस्तक +भगवान +इनमें +पूर्ण +लाभ +टीम +बैंक +अवधि +भिन्न +खिलाड़ी +ली +सदस्यों +आने +प्रयोक्ता +कार्यक्रम +सीमा +समर्थन +संस्कृति +े +अंतिम +स्कूल +बने +विकि +टी +अ +पाया +नही +र +सदी +फरवरी +मुझे +सन +परिचय +लेने +मेरे +पार्टी +उत्तरी +लिखने +१८ +दिसम्बर +राम +भर +विशिष्ट +मी +क्षमता +प्रयास +सहित +पश्चिमी +सिद्धांत +दर्शन +सभा +किंतु +वर्णन +विधि +श्रृंखला +बजे +संगठन +गीत +एम +बेबल +राजधानी +प्रभावित +पौडी +ठीक +सुझाव +गति +प्रबंधन +व्यापार +सामग्री +ना +एन +दृष्टि +दिया। +पद +ब्रजभाषा +म +सूचना +शोध +नामांकन +अवधी +लोकप्रिय +आन्ध्र +हाथ +रहने +विस्तार +ऑस्ट्रेलिया +वृद्धि +फ़रवरी +११ +जैसा +आर +कहानी +व्यवस्था +क्रिकेट +बागेश्वर +पृथ्वी +चमोली +गांव +युग +यौगिक +कहीं +पूर्वी +२० +सुरक्षा +मुखपृष्ठ +स्पष्ट +१६ +मिलता +देवी +यही +बुंदेली +सामने +प्रवेश +यूरोप +रखने +दिए +जॉन +जिन्हें +दूसरा +पूरे +स्थानीय +आते +नियंत्रण +चीनी +दिखाई +प्रकाशन +ऊर्जा +प्राकृतिक +की। +जैन +लगता +बनाए +अमरीकी +कवि +व्यापक +दर +वजह +वहाँ +परीक्षण +लंदन +प +ी +बदल +जाए +अदिलाबादु +शासक +खोज +द्वितीय +बस्तर +मदद +योजना +ब्रिटेन +प्रस्तुत +जे +धार्मिक +आर्थिक +सहायक +लेखन +शुरुआत +मिल +डॉ +प्रौद्योगिकी +शासन +स्रोत +रायगढ़ +वैज्ञानिक +कमी +आपके +मिनट +पत्र +निर्वाचन +रक्त +ऑफिस +गूगल +संग्रह +उद्योग +राष्ट्र +एशिया +सांस्कृतिक +पदार्थ +इनका +आपका +मुंबई +हिस्सा +दृष्टिकोण +उद्देश्य +वी +ह +दूरी +आता +अनुवाद +वो +पीछे +भूषण +क्रिया +स्वास्थ्य +पैदा +केंद्र +२०११ +अच्छे +पद्म +शब्दों +ऐतिहासिक +गैर +पिथोरागढ +छोटी +६ +सार्वजनिक +कपूर +प्रेम +मुंगेर +रहती +चैनल +समस्या +कनाडा +अंतर्गत +देवनागरी +राष्ट्रपति +जिसने +बैंड +साम्राज्य +कॉलेज +मगही +प्रयुक्त +पुत्र +अनुसंधान +पहचान +निर्मित +किमी +बंद +प्रतिशत +लगे +अंतर्राष्ट्रीय +ताकि +भूमि +मानक +इंग्लैंड +सके +प्रारंभिक +सन्दर्भ +थीं +अंगिका +दिशा +जर्मनी +१९ +संकेत +बच्चों +द्वीप +समाचार +अफ्रीका +घोषणा +रह +बंगाल +भाषाओं +घंटे +हाल +राजस्थान +वहां +आया +उपन्यास +कानून +दिनों +अभिनेत्री +खिलाफ +सदर +अनुमति +हवाई +टीवी +समाप्त +मीडिया +उपचार +हमारे +जनता +नियम +संक्षेप +मन +मिलियन +चौपाल +उपकरण +राज +भीतर +चेन्नई +२८ +कृष्ण +क्लिक +३० +कविता +कथा +सूर्य +प्रेस +वीडियो +स्वतंत्रता +वन +राजनीतिक +आमतौर +देती +दृश्य +न्यू +योग्य +लागू +मिला +बताया +मैच +जिसकी +सा +मीटर +नेटवर्क +रोचक +भोजन +हूँ +मौजूद +धीरे +१७ +संभव +माता +नृत्य +७ +महत्व +परन्तु +आशा +डॉलर +शायद +आयोजित +सम्मान +युगल +कांग्रेस +सफल +उर्दू +उनमें +वापस +चाहिए। +दें +मनुष्य +लाख +महान +निजी +उल्लेख +जैसी +इनकी +व्यवहार +पन्ने +नीति +जाति +एल +पोस्टर +विशाल +बल्कि +संचालित +देखने +विवाह +अच्छा +ख़ान +२६ +इ +कृष्णा +वंश +जापान +केन्द्र +मेरी +तमिल +देख +विजेता +वेब +शिव +सिर्फ +न्यूयॉर्क +भाई +यूरोपीय +राजीव +प्रयोगस्थल +उत्पाद +मंच +पांच +०५ +पंजाब +०४ +राजमार्ग +मॉडल +कंप्यूटर +स्वीकार +अंतर +कार्बनिक +सक्रिय +परंतु +लखीसराय +किलोमीटर +यमकेश्वर +चला +आलेख +पड़ता +उसमें +ज्ञानसन्दूक +आपने +हमें +मान +इंजन +तहत +पत्रिका +अवस्था +९ +चम्पावत +ं +सहयोग +मौलिक +मामले +अच्छी +तिथि +आरंभ +स्वतंत्र +बल +बाजार +८ +प्रारंभ +मूल्य +सरल +वास्तव +यू +उससे +तुम +मैंने +पुनः +सागर +पक्ष +०६ +छोड़ +खाना +अनुभव +टू +तरफ +बस +विजय +महाराष्ट्र +समुद्र +उचित +रेडियो +चल +हटाने +खुद +समीक्षाएँ +जीव +तेल +दिल +उम्र +जर्मन +ग्रंथ +रूस +संपर्क +बौक्स +रखें +गंगा +एल्बम +राय +पाठ +हासिल +निश्चित +सीमित +सात +प्रांत +गई। +नेपाल +दक्षिणी +काव्य +निर्णय +छोटा +२५ +डिजाइन +रात +हों +लगाया +वास्तविक +पूछे +ज्ञात +प्रकृति +कार +गए। +निर्वाचित +तरीके +त +ज +चुनाव +किन्तु +बढ़ +२१ +हो। +जीत +विपरीत +दस +वर्मन +औसत +इंडिया +सम्मानित +२२ +नाटक +अधिनियम +वस्तु +संरचना +मत +सर्वाधिक +लेखों +विश्वास +मास +संकिपा +वायु +शीघ्र +घटना +निम्न +विरोध +सप्ताह +स्वरूप +प्रवेशद्वार +सितम्बर +गुरु +सॉफ्टवेयर +निर्धारित +विद्युत +रक्षा +पूर्णिमा +पड़ा +बावजूद +बेहतर +वर्ल्ड +चुका +भारी +मगध +समुदाय +क्यों +ऑस्ट्रेलियाई +जनगणना +लीग +अंक +मिलती +भागों +बाल +भेज +कप +कोरिया +कर्नाटक +मात्र +हुई। +अत्यंत +तत्व +महाभारत +ओ +अरब +पूजा +निर्माता +रोमन +विदेशी +अल +पर्वत +पिछले +इनसे +पार्क +स्थानों +जिन +धारा +चुके +मिली +जाकर +बदलने +स्वामी +सम्मेलन +२३ +बनाये +अल्मोडा +शो +जंक्शन +मन्दिर +गलत +सफलता +लिपि +पाए +योग +निर्भर +सिस्टम +प्रसाद +गांधी +प्रचार +फ्रांस +वर्मा +जिन्होंने +रहें +बौद्ध +बच्चे +आंदोलन +एच +तंत्र +मोबाइल +कोशिश +अध्यक्ष +गैस +प्यार +सारे +ल +लक्ष्य +अवश्य +लेते +आसपास +चरण +पर्याप्त +आयु +शर्मा +कार्बन +सुरक्षित +कोलकाता +शीर्ष +२७ +मै +समिति +धन +विवरण +सुविधा +खान +आती +जिनके +यद्यपि +मामलों +प्रशिक्षण +सिटी +कैंसर +पात्र +इतना +रिपोर्ट +नेतृत्व +महिलाओं +फल +महीने +सड़क +देव +मान्यता +क्लब +अनंतपुर +क्रम +य +बजाय +साँचे +उप +२४ +विश्लेषण +आनन्द +यूनानी +चाहते +राज्यों +फाइनल +अवार्ड +जुड़े +अत्यधिक +तकनीक +अज्ञात +निकट +सेंट +चलता +रेखा +निर्देशक +इंडियन +मानते +देवता +जांच +हे +पत्नी +इंटरनेट +केरल +जोखिम +रिकॉर्ड +बदलाव +डिग्री +प्रतीक +जाएगा +अतः +पालन +खंड +विष्णु +भौतिक +जिनका +अकादमी +होगा। +गुण +वित्तीय +क्षेत्रफल +कर्नूलु +करें। +भाव +तापमान +०७ +अनुमान +डे +अमरीका +रासायनिक +च +ग +अभिनय +पत्थर +खाता +किस +गणराज्य +टेस्ट +चोर +इत्यादि +शुद्ध +होगी +भिकियासैण +संघर्ष +अंतरराष्ट्रीय +लगातार +माँ +उल्लेखनीय +रखते +लक्षण +जेम्स +ग्रह +प्राय +वही +औद्योगिक +संक्षिप्त +२००६ +विमान +टिप्पणी +नागरिक +ध्वनि +याद +संचार +बराबर +प्रधान +अमेरिकन +पारंपरिक +युक्त +अत +पुरी +प्रतिक्रिया +शाह +चक्र +अवसर +हमेशा +शारीरिक +हंडिया +आबादी +तट +लाइन +विकल्प +अंग +लोकसभा +खाद्य +पर्यावरण +संसार +विवाद +बनने +करीब +व्यक्तियों +० +वैदिक +बिक्री +ब +निम्नलिखित +कोशिका +पार +परमाणु +भवन +समझ +नष्ट +स्वर +दुर्ग +जितना +प्रकट +फॉर +विमानक्षेत्र +रख +रुप +शहरों +तकनीकी +लखनऊ +मुद्रा +हिस्से +झील +आयोजन +इकाई +मील +समस्त +संरक्षण +अंदर +संस्था +परंपरा +सतह +कार्यों +विद्यालय +संसद +अभियान +सिद्ध +मुख्यालय +प्रस्ताव +सीधे +सर्वोच्च +डालकर +वाहन +गुजरात +उपयुक्त +राशि +बोली +सक्षम +अधिकतर +नेशनल +प्राथमिक +मौत +इसने +गणित +अली +व्यवसाय +हवा +मिट्टी +अगले +फिल्मों +चले +डेविड +मिलते +बनाई +महल +आक्रमण +रे +राजनीति +मंत्री +गंभीर +शाखा +अम्ल +हटा +तटस्थ +भविष्य +ईश्वर +आए +वि +दावा +प्रसारण +जीवित +कड़ी +रखें। +लिमिटेड +अन्दर +क्रांति +लिखे +मैदान +धातु +एफ +सम्बन्ध +विलियम +हृदय +संभावना +वातावरण +न्यायालय +लगाने +सैन्य +परिवहन +परिषद +चारों +पवित्र +योगदानकर्ताओ +गुणवत्ता +खगड़िया +शेष +करे +ला +युवा +नियमित +ऑन +सर +पसंद +दबाव +ईरान +लागत +०९ +०८ +२९ +अधिकारी +उनसे +कहना +बोर्ड +ग्रहण +अशोक +स्टार +जान +दिखाया +ग्राम +स्पेन +नीतियाँ +सभ्य +००० +समारोह +संविधान +इटली +आठ +संग्रहालय +तर्क +दूतावास +पाने +लिया। +पाँच +थलीसैंण +लगी +जन +ताप +परिणामस्वरूप +लॉग +लिखी +रॉक +कार्ड +प्रेरित +आगंतुकों +फूल +तेलगू +लेता +मिले +रोगी +आक्षेप +जरूरत +गठन +व्यक्त +भुगतान +मौसम +मीडियाविकि +अन्तर्राष्ट्रीय +पदार्थों +पूर्वाग्रह +रहे। +शादी +पुरा +विषयों +बिलियन +ढंग +आदेश +लंबे +काउंटी +धन्यवाद +मुस्लिम +विरोधी +वेल्स +लिखें। +पुरानी +कांडा +रानी +विभाजित +मिलकर +तारा +वैसे +ईसाई +पू +शिकार +ज्ञानसंदूक +नेता +शास्त्र +कौन +राजवंश +ब्लैक +अस्तित्व +धारी +प्र +०३ +तेजी +रायपुर +संवाद +किनारे +टाइम्स +भार +सिर +उत्तरप्रदेश +छह +आलोचना +दिये +गुप्त +गेम +नियंत्रित +पुराण +उद्यान +डालें। +हिंदू +डीवीडी +परीक्षा +वालों +घरेलू +वस्तुओं +व्याख्या +पौराणिक +अर्थात +फूलपुर +करोड़ +दिवस +लघु +जिसमे +पिथौरागढ +विज्ञापन +पेश +चर्च +घोषित +कंपनियों +पशु +पाएँ +दर्द +चलते +समाधान +माइकल +सामना +पूछें +लड़ाई +जोड़ें। +संपादित +जनरल +विविध +मिश्र +आग +भावना +टिल्ड +कैलंडर +हत्या +ग्रेगोरी +प्रशासन +रिलीज़ +खास +मध्यम +ज्यादातर +अरबी +रानीखेत +देखते +पाई +आसानी +अंश +कश्मीर +नवागंतुकों +प्रभावी +लिख +किताब +जीन +इंडियाना +चूंकि +सत्य +गंगोलीहाट +नामांकित +कोशिकाओं +कार्यालय +छात्र +मस्तिष्क +डेटा +अनुनाद +मंडल +चुकी +नारायण +कर्म +संपूर्ण +प्रतिनिधित्व +पहुंचती +तेज +अपेक्षा +जाएगा। +व्यंजन +आत्मा +वैश्विक +मांग +सेट +इन्होंने +सम्पूर्ण +बदलें +लग +एशियाई +रोड +ऑनलाइन +इस्लाम +दास +संत +पक्षी +बीबीसी +व्यावसायिक +सीज़न +फुट +जानते +संक्रमण +विचारों +चाहता +मतलब +विरुद्ध +रसायन +निवेश +वर्षा +प्रमंडल +संस्कार +केन्द्रीय +अंतरिक्ष +ध्वज +विशेषता +बाकी +थीं। +यूनिवर्सिटी +शंकर +दैनिक +आचार्य +सं +अनुरोध +गायक +मानसिक +जमा +हाउस +मंत्रालय +पहुंच +जॉर्ज +उपस्थित +मार +प्रधानमंत्री +अंततः +घनत्व +थराली +दूध +सेवाओं +वर्णित +नियमों +यूनाइटेड +साथी +विभाजन +आपकी +चौबटाखाल +सम्मिलित +प्रवाह +गोल +हुए। +बिलासपुर +कह +जलवायु +ब्राह्मण +समर्पित +निवास +फोन +प्रमाण +पैमाने +बिजली +रोहित +शांति +अति +उत्पत्ति +तीसरे +आनंद +हमारी +एकमात्र +नुकसान +मिलने +पे +सौ +घटनाओं +मां +प्रायः +भौतिकी +कठिन +माने +घाटी +अधीन +स्थिर +लेना +उपयोगी +रखना +छूटती +द्वार +वेद +चैम्पियनशिप +बिंदु +जुड़ा +कल्पना +आये +संपादन +तारे +दें। +परिभाषित +उ +सिद्धार्थ +जापानी +ऊंचाई +भौगोलिक +समुद्री +आदमी +उपकरणों +स्त्री +वाक्य +निर्देश +मशीन +०२ +सत्र +फुटबॉल +घाट +उपग्रह +पंथ +बहुधा +हाइड्रोजन +लंबी +श +सुंदर +दौर +रखता +फ़ाइल +मोहन +देकर +काला +नंबर +उपस्थिति +दवा +जीवनी +आंतरिक +परिवर्तित +ज्ञानकोष +वहीं +आय +समझा +निगम +वृक्ष +पॉल +बुद्ध +बाज़ार +मराठी +रूसी +जय +ग्रैंड +संचालन +तत्वों +व्यक्तित्व +कीया +३१ +कारणों +बनाना +अपराध +फिल्में +चक +व्यास +चाहे +छोड़कर +नमस्कार +टेलीविजन +डा +वितरण +एक्स +पुराना +रामायण +बेरीनाग +ग्रामीण +सेंटर +लाइसेंस +मित्र +छात्रों +अध्याय +शेयर +अभाव +मानना +विद्वानों +जनजातियां +वैकल्पिक +तुर्की +जैव +पश्चात +नहीं। +डिजिटल +तारीख़ +समीक्षा +हजार +प्रिय +इतनी +अर्जुन +शराब +स्मृति +जीता +उच्चारण +श्रीलंका +बीजापुर +निकल +स्वीडन +सत्ता +संपत्ति +गर्म +बीमारी +अर्थात् +५० +सम्राट +व्रत +मिश्रण +वार्षिक +प्रत्यक्ष +अंकित +रॉबर्ट +समूहों +आपूर्ति +इंजीनियरिंग +कैलिफोर्निया +उनको +गेंद +इच्छा +रन +ऋषि +समस्याओं +आन्दोलन +अपेक्षाकृत +रोम +चाहिये +चलने +गतिविधियों +गाने +विम्बलडन +हैरी +एण्ड +इंच +सेवाएं +वेस्ट +वें +जाये +पहुँच +हूं +श्रेष्ठ +रहा। +हार +अस्पताल +निरंतर +नियुक्त +तारों +ख +केंद्रीय +वर्तनी +धारण +दान +वाराणसी +स्टूडियो +रोगियों +कुकर्म +साधन +जटिल +अक्षर +देंगे +स्कोर +उत्पादों +प्रोटीन +अनिवार्य +२००१ +कायमगंज +सौर +सरगुजा +साबित +ऊँचाई +लीला +सैनिक +स्टेडियम +रायगढ +पर्व +जयपुर +व्याकरण +रावत +इसलिये +करेगा +तीव्र +प्रकाशक +कृतियाँ +प्रसार +नोबेल +सभ्यता +परिसर +अफ़्रीका +राजनैतिक +इलाज +साहित्यिक +सतपुली +लिखित +फ्रेंच +देखे +ऋण +अकबर +सोवियत +हमला +प्रोग्राम +मिस्र +डाला +छत्तीसगढ +आयोग +पुरुषों +रस +सुनिश्चित +पेरिस +साहित्यकार +परिभाषा +डाटा +अर्थव्यवस्था +महाराज +ओम +सह +पेज +जिनकी +वर्ण +दर्ज +भारती +तभी +तय +एसोसिएशन +अनुपात +झारखंड +जोड़ा +पुन +छत्तीसगढ़ी +यानि +लकड़ी +त्वचा +अधिकतम +कोरबा +देखकर +डाल +पुरालेख +कोइल +बढ़ती +सफेद +प्रतीत +कानूनी +चयन +बनता +हाथों +जल्दी +चार्ल्स +ग्रन्थ +रोक +कारक +खाने +अभ्यास +कैरियर +वर्गीकरण +सर्वेक्षण +नारायणपुर +मिश्रित +ें +तमिलनाडु +प्राप्ति +आकर्षित +भेजा +बनाकर +संग्राम +किले +अड्डा +कहलाता +महसूस +मार्क +माल +वजन +फ़्रेंच +ठोस +उपयोगकर्ता +चम्पा +सलाह +भेद +काफ़ी +लोगो +खाते +निर्देशन +स्वर्ण +बनाते +नोकिया +मूर्ति +हद +रोकने +समाप्ति +अकाउंट +कार्यक्रमों +ग्रीक +संधि +लंबाई +निवासी +दौरे +चाहें +क्षेत्रीय +स्थायी +किंग +न्याय +मोटर +संभवतः +बनाता +पेड़ +तल +पति +वां +कराया +शुरूआत +प्रारूप +काले +कांकेर +रखे +पौधों +खेलों +०० +काशी +मस्जिद +हरा +आकर्षण +नयी +रखी +मजबूत +कडप +आजकल +टंकण +साक्षात्कार +तीसरी +खेती +महासागर +लाया +जोड़ +सामान्यतः +सम्बंधित +सुन्दर +रचित +जांजगीर +पृष्ठों +दीवार +उन्होने +विद्या +लाने +पड़ती +संयोजन +तीसरा +पड़ +रोगों +संसाधन +भाषाएँ +मानचित्र +जमीन +देहरादून +मुगल +कोर्ट +कवर्धा +धमतरी +जशपुर +पौधे +कदम +आकर +बढ़ा +अधिकारियों +आरोप +मिलाकर +बढ़ाने +प्रशासनिक +हमले +टाइम +प्रेरणा +उड़ान +शक्तिशाली +पीपी +महासमुन्द +विधानसभा +फीट +प्रगति +स्नातक +सूक्ष्म +जवाब +कम्प्यूटर +अप +छवि +फ़िल्मों +भ +शुल्क +विभूतियाँ +कलाकारों +संकट +संभावित +दिशानिर्देश +जोर +विधान +आहार +गोठ +उपाधि +राजनांदगांव +जम्मू +सतनाम +कर्णप्रयाग +थोड़ा +बाबा +साइट +तथापि +दन्तेवाड़ा +यानी +अमर +मार्टिन +तुरंत +जिले। +लाइव +पुनःप्राप्त +निर्धारण +तत्कालीन +कक्षा +सारी +प्रजातियों +गये। +करो +मूल्यांकन +द्वाराहाट +राजशाही +घई +होगी। +गैरसैण +हॉल +बिल +ऐ +रूपों +मंगल +जानी +चित्रण +नीतियां +शिक्षण +अवधारणा +चेक +किला +तीनों +मारे +इमारत +आवासीय +किंगडम +राजीवमास +चुना +आँकड़े +फलस्वरूप +करेंगे +ज्योतिष +यंत्र +ग्राहक +चित्रों +नौ +सल्ट +उम्मीदवार +कोश्याँकुटोली +बीज +उत्कृष्ट +०१ +कम्पनी +महात्मा +खर्च +केंद्रित +सिन्हा +हाई +प्रबंधकों +मुश्किल +नर +गाँधी +बनाएं +करनी +हूँ। +स्टेट +प् +दार्शनिक +निकाल +मनोरंजन +पुस्तकालय +सोचते +जेल +हिमालय +पा +जहाज +तरल +यूनिकोड +सैन +हास्य +पैर +दि +दी। +खराब +ख़ुदा +कृति +पुष्टि +हल्द्वानी +असम +अर्थशास्त्र +सेवन +ग्रंथों +कड़ियां +बदले +पुस्तकों +हेनरी +रिचर्ड +परम +सके। +पृ +रहना +हल +सर्वप्रथम +सामान +काली +चेतावनी +मनोविज्ञान +बॉक्स +छोड़ने +संगठनों +तारामंडल +हैदराबाद +छिबरामऊ +मुख्यतः +टैग +४० +यहूदी +विद्रोह +दर्शकों +ग्रुप +जोशी +डीडीहाट +सेन +गरुङ +कीमत +पीटर +कृत्रिम +विपणन +प्राण +आस +बुनियादी +वीर +जल्द +ऊपरी +टिप्पणियाँ +नज़र +पहुंचा +लेखकों +ईंधन +गुणों +२००४ +स्ट्रीट +बचपन +लैटिन +मलयालम +हिमाचल +सरस्वती +स्वामित्व +जंगल +भनोली +भक्ति +श्रीकृष्ण +नवीन +मैन +पीढ़ी +शहरी +लव +अररिया +अनुबंध +विश्वभर +स्मारक +पुर्णीमा +देवताओं +पढ़ें +प्रसारित +परिस्थितियों +रास्ते +टाटा +वा +तरीका +विषाणु +अनुप्रयोग +ईरानी +यात्री +संशोधन +क्रमांक +पंडित +ते +माह +मुक्ति +गहराई +सुबह +यहीं +नाथ +संबद्ध +उत्तम +प्रजाति +मापन +गद्य +टीका +वित्त +विख्यात +अवतार +उपनिषद +दीया +मुहम्मद +राजाओं +फैसला +परंपरागत +जर्नल +व्यापारिक +होंगे +एयर +चौखुटिया +मथुरा +लगते +उसको +तनाव +सिंगापुर +उत्सव +पुणे +अभिव्यक्ति +बढ़ावा +इसको +बच्चन +द्रव +अनुरूप +एट +मेट्रो +उत्सर्जन +एलबम +हरियाणा +चलती +वाणिज्यिक +डॉक्टर +चली +मानी +लगा। +लॉस +सैनिकों +सवाल +२००५ +आरंभिक +निदान +अतरौली +कराने +मालिक +देर +तीर्थ +विदेश +यथा +प्रबंध +संपादक +जैविक +दोस्त +मि +अनुकूल +संस्थापक +इंटरनेशनल +स्लैम +सकारात्मक +टाइप +पुस्तकें +रा +मियामी +लगे। +ड +घटक +निदेशक +इतने +प्रतिनिधि +मितुल +अंग्रेजों +दोनो +बांग्लादेश +वनस्पति +बढ़ने +बंदरगाह +आसान +सटीक +मनाया +भू +समकालीन +पाठक +दोष +औपचारिक +डिस्क +बेटी +संदर्भित +निभाई +राव +सूरज +मगर +चलचित्र +मछली +देखी +जगत +ज़्यादा +सर्वर +लम्बाई +ग्रेट +कर्मचारियों +पंजाबी +अगला +शाही +दर्जा +चिकित्सक +विकार +फैला +शुक्ल +प्रजनन +हां +सदा +अग्रणी +नायक +गृह +धन्यवाद। +जालस्थल +आवाज +बनाम +कपकोट +संघीय +बिग +गलती +विविधता +नो +लगती +पेट +रिलीज +विद्वान +अन्तिम +कॉपीराइट +नमक +अधिकारों +प्रणालियों +युकेश +आर्ट +रॉयल +बालक +पश्चात् +हटाया +पर्यटक +आर्य +प्रीमियर +शब्दावली +परत +सिद्धांतों +हमारा +अकार्बनिक +चोट +कौशल +प्रारम्भ +विकेट +गुना +ब्रह्म +आयरलैंड +पेशेवर +इस्पात +ठाकुर +अग्नि +कोश +रुचि +उपनाम +दत्त +उम्मीद +पशुओं +श्रेय +मुम्बई +निकाला +सिख +पदक +कवियों +इसीलिए +मार्शल +बॉलीवुड +खन्ना +प्रवृत्ति +यौन +रचनाओं +उड़ीसा +तेलुगू +आश्रम +अस्पष्ट +माइक्रोसॉफ्ट +महत्त्वपूर्ण +चयनित +शास्त्रीय +कर्मचारी +जैक +खो +विशेषकर +शब्दकोष +स्क्रीन +प्रतिमा +बर्फ +फारसी +महाराजा +ब्लू +शून्य +जरूरी +आनेवालों +दौरा +प्रतिभा +सच +मौजूदा +क्षति +स्थलों +खून +फ़िल्में +प्रशंसा +होटल +सेल +सालों +थ +दुर्गा +हाँ +स्मिथ +बुक +नोट +रचयिता +शिखर +नेहरू +ब्रांड +सुख +समझने +मुंह +महाविद्यालय +ईस्ट +शृंखला +बचाने +आध्यात्मिक +पुल +त्याग +आविष्कार +हजारों +कहता +जाय +प्रक्रियाओं +विलय +दूसरों +जाए। +२००० +वापसी +आकाश +थॉमस +इलेक्ट्रॉनिक +कडियाँ +संगीतकार +परस्पर +मुख्यमंत्री +उपभोक्ता +प्राणी +होनी +आउट +स्व +उपनिषदों +वक्त +कक्ष +यांत्रिक +आंशिक +बांग्ला +संकोच +शनि +ट +हिन्द +पट्टी +लंबा +कन्या +जीवों +नैतिक +किशोर +फ्रांसीसी +वस्त्र +शिकागो +नदियों +संस्थाओं +ो +गतिविधि +कठोर +सोने +कंपनियां +बेटे +प्रतिरोध +दवाओं +न्यूनतम +खैर +गरीब +मेला +निकटतम +स्थानांतरित +लौट +विटामिन +जोड़ने +ब्रायन +यादव +सहारा +अफ्रीकी +सिनेमा +रचनात्मक +नामों +यज्ञ +स्थितियों +तृतीय +हुये +रिंग +पोषण +कहने +उपाय +विशेषज्ञ +चार्ट +क्लासिक +मानवीय +कार्रवाई +एक्सप्रेस +निर्देशित +सम्बन्धित +ग्राहकों +चलाने +अड्डे +चेतना +देखभाल +रंगों +विकी +कल +संबंधों +सम्पर्क +निष्कर्ष +तंत्रिका +वैज्ञानिकों +टॉम +प्रयत्न +२००३ +पाठ्यक्रम +चिंता +३५ +श्रम +बहन +काल्पनिक +डब्ल्यू +कपड़े +डबल्यू +जातियों +खाड़ी +गीता +हाथी +डिज़ाइन +एकीकृत +कन्नड़ +खतरा +प्रस्तावित +खरीद +अन्त +कार्यरत +ग्रीन +विकिरण +असफल +हानि +लोहाघाट +कानपुर +खिलाड़ियों +छ +सूचित +अयोध्या +स्टॉक +चन्द्र +गवर्नर +लिंक्स +फ़ारसी +खनिज +मंदिरों +गिरावट +पोखरी +सारा +आवाज़ +वायरस +विलियम्स +राधा +सेंट्रल +सहमत +बातें +रामनगर +लिंग +श्वेत +लक्षणों +दर्शनीय +बाराकोट +ऐंड +सन्‌ +रास्ता +वसा +शती +बदला +उन्नत +हिन्दुस्तान +३६ +पृष्ठभूमि +हार्ट +सहज +गिटार +इतालवी +पर्यटकों +हरे +खुले +वर +व्युत्पन्न +जाँच +धारणा +मुख +होली +खड़े +प्रतिष्ठित +पड़ा। +बचने +निवासियों +बरो +लेती +पीठ +पाकिस्तानी +रामचरितमानस +आपस +समझौते +महीनों +कर्ण +हिस्ट्री +सो +पोस्ट +पंक्ति +बहु +संशोधित +कोलंबिया +बचाव +रिकॉर्डिंग +थोड़ी +चुने +चौधरी +अंकों +शाम +बातचीत +ओलम्पिक +गर्मी +फ्लोरिडा +गोली +लाइफ +लम्बी +बम +चावल +बातों +वर्गों +आवास +मिशन +सफ़ेद +४५ +दशा +अपलोड +मेडिकल +जानने +कार्यकारी +सकतें +समीप +संयंत्र +नि +आवेदन +मांस +गहरा +तरीकों +छः +कल्याण +लगने +हुसैन +औ +संजय +जंगली +केन +सुपर +सबूत +साफ +क्रमश +लॉर्ड +समझौता +नाडु +अदालत +आगमन +प्रथा +डालने +औषधि +करवाया +जिम्मेदार +यान +पन्नों +महावीर +सकें +परम्परा +मेक्सिको +गोल्डन +गईं +टन +एकदिवसीय +आदि। +ऑल +१०० +प्रदूषण +अणु +चोपड़ा +भा +संरक्षित +प्रभावशाली +पुचः +जुड़ी +प्रोत्साहित +तल्ला +साधना +न्यूटन +लोकप्रियता +भरा +प्रार्थना +बंगाली +द्रव्यमान +व्यावहारिक +ट्रैक +सावधान +बैठक +तुम्हारे +पॉटर +रथ +प्रोग्रामिंग +कही +कमल +मशहूर +नजर +धरती +स्वाभाविक +चेहरे +सकता। +शिशु +कोण +पॉप +मन्त्र +५१ +निवेदन +अकेले +आवृत्ति +३२ +उठा +कवर +गरम +शैक्षिक +वास्तुकला +पाते +खूबसूरत +एसिड +होता। +जायेगा +पड़े +सीजन +नीला +योग्यता +वैध +ग्लोबल +पथ +बीमा +हिस्सों +माप +मैने +बारह +उल्लंघन +जानवरों +प्रवासी +साहब +एजेंसी +हिट +सुविधाओं +सोच +रवि +गीतों +पेन +गुजराती +अगली +दर्शाया +पतन +चित्रित +आकृति +मैसूर +बुद्धि +मंत्र +मनुष्यों +पत्रकार +पेय +विद्यमान +मादा +बोलने +मना +बेस +सहयोगी +हराया +समीकरण +लिखते +फसल +संहिता +लें +तिलक +प्रोफेसर +सीधा +आकर्षक +संज्ञा +मोटे +वार +खगोलीय +क्रमशः +समर्थक +स्नान +नकारात्मक +नक्षत्र +पहुंचने +चित्रकार +दुर्लभ +सिद्धान्त +भाँति +छाया +पूंजी +आलोचक +अपनाया +बेहद +खड़ा +सका +उदय +भूल +यमुना +क्रेडिट +साउथ +नैदानिक +हिल +में। +फ +नील +प्रयोगशाला +५२ +शासकों +मा +हिसाब +इन्हीं +रॉय +गाय +घायल +ऋतु +तार +लम्बे +३८ +संपन्न +क्रिस +कृत +उतना +नामकरण +स्वाद +मनोवैज्ञानिक +भय +नौसेना +हावड़ा +४८ +श्याम +कार्यवाही +हस्तक्षेप +दंड +दुबई +किस्म +अभियांत्रिकी +फ़िल्मफ़ेयर +मोहम्मद +उर्जा +पारित +गोरखपुर +अस्थायी +स्तंभ +मुसलमानों +असामान्य +कैथोलिक +वर्गीकृत +पाप +मनीष +श्रेणियों +भरे +४६ +पढ़ने +बिल्कुल +खुला +उद्यम +मूलतः +जोड़ी +युनाइटेड +दरबार +मद्रास +निकालने +विरासत +संगम +निहित +गिर +कथन +दाब +आवश्यकताओं +कहानियों +ऑक्सफोर्ड +आफ +उन्हीं +आधा +मर +सोसाइटी +ब्लॉग +मल्ला +कालाढूगी +आकलन +अत्यन्त +पकड़ +चाहिये। +भरी +भाषण +आधे +रत्न +टूर +नाना +संस्थानों +कालेज +शल्य +।। +नौकरी +जुड़ने +गा +मास्टर +किरदार +कुशल +पक्षियों +अधिग्रहण +मजबूर +खड़ी +बताते +अनिल +महाद्वीप +हथियार +कलकत्ता +प्लास्टिक +पायलट +स्वस्थ +जिनसे +रचनाएँ +शिवाजी +परिक्रमा +२००२ +भोपाल +पटकथा +खत्म +ड्राइव +रूपांतरण +भक्त +४२ +अन्यथा +उच्चतम +बढ़ता +असर +रेड +घरों +व्हाइट +आना +खाली +जॉनी +राहुल +कमजोर +ब्राज़ील +श्रीमती +चाय +रखकर +ॐ +एपिसोड +मुसलमान +जाया +एडवर्ड +पारी +बांध +विस्फोट +उर्फ +गुरू +डच +प्रमाणित +समग्र +मतदान +कण +पाटी +प्रोटोकॉल +विकिपीडीया +हिंसा +आजादी +तस्वीर +४७ +चुनौती +क्रांतिकारी +शेर +न्यूजीलैंड +ऑक्सीजन +बनते +निगरानी +व्यवस्थित +सर्विस +आखिरी +चिन्ह +समृद्ध +प्रयासों +रेस +पाता +खतरे +उन्हे +पटेल +बादशाह +गर्भ +हमने +चरम +मुखर्जी +चलकर +पाउंड +जातक +टिप्पणीसूची +न्यायाधीश +५५ +अनुच्छेद +शास्त्री +हि +५३ +पेशकश +बिट +गणेश +जीवाणु +संकलन +पीड़ित +ख़ास +बेस्ट +निकलने +लोहे +ऑव +स्वर्ग +सोसायटी +बेल +भट्ट +बढ़ते +दुर्घटना +त्यौहार +संगणक +विनोद +हालाँकि +न्यूज़ +गहरी +पब्लिक +४३ +तीव्रता +पेटेंट +तिब्बत +पीने +इस्लामी +भीड़ +बहादुर +ड्रामा +सुल्तान +हटाए +अन्तरविकि +साक्षरता +विक्टोरिया +सिनसिनाटी +मठ +प्रतिदिन +सम्बन्धी +निबंध +बनाती +नव +विषय। +तेलुगु +वीकीपीडीया +ऊतक +असली +संसाधनों +जानवर +डाक +बाग +डर +स्रोतों +प्रतिबंध +सोमेश्वर +कब्जा +रहित +अवशेष +वरिष्ठ +बेल्जियम +देशी +जीतने +रणनीति +हें +ताल +द्रव्य +खेला +राजस्व +रीति +गयी। +सजा +उपयोगकर्ताओं +बोस +आलोक +आत्म +फ़्रांस +किसान +गणितीय +ज्वालामुखी +अंगों +ों +बनती +४९ +कायम +खिताब +तुलसी +लक्ष्मी +समानता +वयस्क +शिष्य +संतुलन +अचानक +नदियाँ +नीतियों +नागरिकों +जाल +नामित +नेताओं +पात्रों +सिविल +कप्तान +दुश्मन +चमक +अर्जित +मौखिक +स्वभाव +आनुवंशिक +कितने +भागीदारी +चोरी +रोशन +आलोचकों +बोल +गहरे +गेट +स्तरीय +बता +बहस +जावा +खासकर +पड़ने +दौड़ +३७ +निर्माताओं +विशेषताओं +माई +काट +५६ +सृष्टि +फाउंडेशन +संप्रदाय +उपर +प्रखंड +एटा +प्रकरण +अक्षय +स्कॉटलैंड +राजकुमार +इंग्लिश +आइपी +ध्रुव +मैक +अनुमानित +मधुमेह +गौतम +चरणों +कहे +ि +महादेवी +निम्नांकित +कथित +परिणामों +लिखना +गाड़ी +कॉम +लड़की +उद्धृत +ब्लॉक +३९ +टेलीविज़न +एकता +खेलने +कारों +सांसद +चौथे +सहमति +बचा +गाइड +भले +हा +कां +रिसर्च +ज़मीन +आयुर्वेद +बॉब +मुद्दों +सोडियम +तरंग +चालक +बाघ +साइंस +ग्लोब +सकल +मिलान +बताता +जिलों +जिम +पत्रिकाओं +लगाना +वाशिंगटन +बैंकिंग +प्राणियों +ै +ईमेल +३३ +निर्दिष्ट +पोर्ट +पुर्तगाली +चीज़ +बाबू +अखिल +उदयपुर +चोटी +शक्तियों +मापदंड +ण +घातक +माध्यमिक +मारा +जरिए +इकाइयों +५४ +लेजर +विधियों +खण्ड +देखना +कान +प्रस्तुति +३४ +अक्षांश +कइ +मानकों +गुफा +रखती +सुरक्षीत +होम +करियर +कारकों +पत्रकारिता +पृष्ठ। +प्रचलन +अनुक्रम +इगलास +जूनियर +विनिमय +अनुवादक +विद्यार्थी +निर्यात +शब्दार्थ +केन्द्रित +सम्पादन +बोध +ब्रह्मा +फ़ोन +चाल +ध +अंडे +हनुमान +ज़ +बास्केटबॉल +समापन +राग +छोर +साहिब +शांत +यॉर्क +अद्भुत +राष्ट्रों +सदन +प्रसंग +मोशन +तकनीकों +परामर्श +पैसे +एवम +पं +पृथक +सरदार +माया +मारने +लेबल +टु +निचले +अतिथि +महादेव +परियोजनाओं +दर्शक +विकिपीडियन +जगदीश +विकिपरियोजना +मुख्यत +सीमाओं +मुकाबले +प्रताप +यौगिकों +बजट +५९ +अहमद +चलाया +अहमदाबाद +अनुपम +पूर्ति +पिक्चर +स्कूलों +अंग्रेज +स्वीकृति +बसा +धरोहर +आंकड़े +बैटरी +फूलों +बेटा +गर्मियों +प्रबन्धक +जोड़े +महाकाव्य +जन्मे +गानों +वनों +लेन +बाह +एकत्रित +नेपाली +अमीर +नीदरलैंड +कहानियाँ +मेयर +ऑपरेशन +एक्शन +श्रेणियाँ +४१ +चुंबकीय +मृत +मुद्दे +हित +तोड़ +करे। +बर्मा +कहलगाँव +कहाँ +बैंकों +मेले +ग्रहों +परे +ब्रज +ऑस्टिन +सूचीबद्ध +जरिये +दूरभाष +कितना +प्रभावों +वध +वर्णमाला +कितनी +सचिव +पवन +मैक्स +पिछला +सौंदर्य +लो +खबर +वाह्य +प्रचालन +री +प्रभाकर +पहल +प्रभाग +अनुसरण +पहलू +धूम्रपान +रिकार्ड +प्रशांत +अक्षरों +कथानक +पारिवारिक +लाहौर +भाषाओँ +यात्रियों +घास +जनपद +विचारधारा +बिलकुल +सीता +प्रतिष्ठा +निशान +टॉप +अवैध +दूरसंचार +लौह +अतीत +छत +इंक +पूर्णिया +कोर +एलन +उद्योगों +निष्क्रिय +क्यूबा +वेग +स्टील +टाउन +यूनान +साफ़ +अलंकार +विफल +कुत्ते +सम +करना। +मलेशिया +तैयारी +भव्य +ार +पुत्री +इमामगंज +वकील +४४ +संकेतों +मूल्यों +बाई +भ्रम +पाल +ब्याज +गहन +अंतराल +चौथी +प्रतिस्पर्धा +निश्चय +कारोबार +बच +कोटि +साझा +खुल +लन्दन +सार +राज्यपाल +पराजित +स्नातकोत्तर +रात्रि +शानदार +हॉलीवुड +नाटकों +पीला +ब्राजील +ऊंची +पाये +जोशीमठ +सदस्यता +पैरों +हॉट +आँख +शिक्षक +घिरा +फ़ाइलों +कथाओं +बिगाड़ +रुपये +तू +संदेह +लेखा +क्रिसमस +भूकंप +बुरी +हवेली +बीकानेर +जोधपुर +कहलाते +करनेवाले +दशकों +प्रदेशों +कमरे +वुल्फ़ +जितनी +खतरनाक +गुगल +मामला +रक्तचाप +डा० +रविवार +लीये +स्थापत्य +वाहनों +छूट +हों। +प्रो +जातीय +फंड +चौक +सिक्किम +मिस्टर +टूर्नामेंट +रहमान +जड़ +बनवाया +इलाके +गठबंधन +किरण +गोपाल +कागज +शुभ +मिस +एयरलाइंस +लाखों +तत्काल +अवार्ड्स +मौका +गोल्ड +व्यापारी +हरी +सलाहकार +मनु +फ़र्रूख़ाबाद +अपवाद +मूवी +जोन्स +फ्रॉम +शिकारी +ऑडियो +महेश +गौरव +ऊँचा +कब +सतत +पहाड़ +अनिरुद्ध +अध्ययनों +इंदिरा +उपर्युक्त +एकत्र +महर्षि +भर्ती +सोचा +गुरुआ +शुरुआती +अभियान्त्रिकी +जनवादी +पड़ी +आंख +फ़्राँस +गोवा +जैंती +ट्रस्ट +सर्जरी +संयोग +गिरफ्तार +रामपुर +समाजवादी +सृजन +बपतिस्मा +कोष +आराम +मैचों +बसे +पैदल +तलाश +थियेटर +शुष्क +विश्वयुद्ध +प्रतिद्वंदी +परिवर्तनों +एकदम +भ्रूण +मासिक +द्वीपसमूह +माला +फैल +नरेन्द्र +स्टोन +उठाया +सारणी +प्रारम्भिक +बेतालघाट +बीस +त्रुटि +संगठित +क्लास +एड +आयरिश +हू +ललिता +आग्रह +संतान +प्रबल +नहर +डॉन +प्रवाहित +स्पेनिश +बनावट +भाषाएं +करा +प्रोत्साहन +भ्रष्टाचार +उष्णकटिबंधीय +गाना +उपरांत +पोलैंड +बनायी +आएगा। +पादरी +फैशन +बजाए +टूट +सोनी +गले +मलेरिया +बंगलौर +पढ़ाई +क्रिस्टल +चौड़ाई +जोकि +व्यय +मिला। +विवेक +अब्दुल +परिवारों +बाधा +भूत +रंगीन +राजेश +नींव +हाइड्रोकार्बन +पीले +राकेश +बुलाया +इंस्पेक्टर +परिचित +वेतन +इलेक्ट्रिक +तरी +खोला +पदों +मेन +स्तरों +रोजगार +डोमेन +मानता +सेकंड +६० +ईसवी +सिरे +नाइट +गभाना +यथार्थ +लि +कीट +भावनाओं +नरेश +करार +जानता +कार्यकाल +सिडनी +रमेश +परिमाण +भरत +कार्ल +खोल +म्यूज़िक +पठार +शाखाओं +गुप्ता +कार्लो +तिरवा +वर्षीय +चक्रवर्ती +दिव्य +चंद्र +पावर +विथ +पूरक +मुफ्त +ग्रस्त +रोज़ +समुदायों +शैक्षणिक +नीले +भिन्नता +फ़ +देन +जाएँ +अनेकों +काउंसिल +प्रतिद्वंद्वी +माइक +चालू +सम्भव +क्रियाओं +शहीद +विश्वविद्यालयों +चौथा +सदैव +सुधीर +नागपुर +दु +नवाब +स्पर्श +कोट +दलों +लगाए +इतिहासकार +ओवर +फ़तेहाबाद +ऑस्ट्रिया +हार्ड +मुकदमा +स्टीव +चीज +पायी +बादल +आकाशगंगा +आवरण +भेजने +सुनील +कुश्ती +ईसापूर्व +२०० +मुनि +स् +बृहस्पति +प्रयोगों +बयान +खाँ +शब्दकोश +स्वचालित +सिम्बल +पसंदीदा +उत्तराधिकारी +संसदीय +गायन +क्षमा +आतंकवाद +पत्रों +हरिद्वार +लगाकर +अतएव +गार्डन +बैठे +मदन +चौहान +चन्द्रमा +उठाने +जायें +अर्ध +तारीख +डाउनलोड +अनु +ओलंपिक +श्रंखला +दिखाने +अमिताभ +मौर्य +मुताबिक +प्रपात +फोटो +लक्ष्मण +मालूम +देगा +अपील +लेंस +स्पेस +बिन्दु +द्वीपों +स्विट्ज़रलैंड +अर्जेंटीना +पूछा +वोट +अकाल +शत्रु +कबीर +आचरण +सफलतापूर्वक +एक्सचेंज +उत्तराखंड +शिकायत +शंकराचार्य +धारावाहिक +दृश्यों +१९९० +तूफान +सड़कों +अपेक्षित +बाढ़ +प्रोजेक्ट +पहुँचने +हूं। +ग्रांड +उन्नति +कच्चे +स्वीकृत +बहती +व्यायाम +प्रयोजन +एरिक +ऑटो +इंटरसिटी +सरलता +उपनगरीय +अनाज +धातुओं +संकल्प +तेरे +धूप +वंशज +परिपथ +घोड़े +मोक्ष +तालाब +असमर्थ +श्रद्धा +विनाश +सापेक्ष +अद्वितीय +सराय +सुरेश +जनजाति +ट्यूब +रहकर +कैम्ब्रिज +श्वसन +सुविधाएं +सूत्रों +बंध +जंगलों +नेत्र +डीएनए +बिलबोर्ड +आदिवासी +दिखने +गाया +आर्थर +नैशनल +सिक्के +वायुयान +समक्ष +समतल +पिछली +छोड़े। +विधा +सीखने +कालीन +बौद्धिक +विधेयक +सक्सेना +खा +यूनियन +परमात्मा +संस्करणों +योद्धा +पैटर्न +स्त्रियों +कर्तव्य +जातियाँ +वंशावली +कमाई +पैसा +वसंत +कहलाती +एंजिल्स +अपोलो +सिंहासन +इनपुट +बस्ती +दीवारों +प्राधिकरण +संभवत +भालू +केबल +पुष्प +सिंचाई +मानने +कॉल +क्रॉस +अभिगम +उपलब्धि +राजनीतिज्ञ +नोट्स +बे +मेजर +ग्वालियर +प्रजातियां +लॉ +प्रसन्न +यूएस +रहेगा +बुरा +रोल +नली +उक्त +राजकीय +हल्के +हंगरी +पैलेस +बनकर +फेर +पुरे +घड़ी +कविताओं +स्वरुप +सेनानी +अवयव +अनुप्रयोगों +कृतियों +ध्रुवीय +विल +इंडोनेशिया +बहुमत +टिकट +कठिनाई +शासनकाल +कार्यान्वयन +दायित्व +जर्सी +वितरित +मूर +टर्मिनस +सुन +जाएगी +फोर्ड +दीपक +चित्रकला +गरीबी +सेमी +तात्पर्य +संलग्न +आश्चर्य +मेहरा +१९९८ +भंडार +परिषद् +लाइब्रेरी +बंधन +इण्डिया +कोयला +महमूद +सुना +नंदीग्राम +संतोष +यूके +जागरण +बदलकर +नींद +बचे +किसानों +खुशी +स्पोर्ट्स +बलों +भंग +कहानियां +सफाई +रहस्य +कणों +किशन +वृत्त +अरुण +मानस +प्रेमी +हमलों +जीते +नमूने +त्वरित +नम्बर +शरण +आतंकवादी +रंगमंच +टुकड़े +निकलता +ठंडा +खेत +गेम्स +राजेन्द्र +तालिका +तटीय +दिनेश +भंडारण +निकला +मध्यकालीन +५०० +पान +चक्कर +ब्राउन +वाणी +असाधारण +यकृत +बोलते +रोटी +झूठ +पौधा +वेदों +संक्रमित +जितने +खूब +नाभिकीय +ज्यामिति +रेटिंग +जिम्मेदारी +प्रेमचंद +एजेंट +निरीक्षण +लुईस +नित्य +मेमोरी +उतनी +उसपर +पड़ोसी +तुम्हें +वचन +लोकतंत्र +पार्श्व +संवेदनशील +उत्पादित +सीरीज +कॉर्पोरेट +सूचकांक +चैनलों +अनंत +नीतिया +रिकॉर्ड्स +ज़रूरत +भावी +होल +विवादास्पद +पिनकोड +सरकारों +पहलुओं +जादू +तपस्या +विहार +मोटी +रुपए +अपितु +व्यंग्य +सीधी +सिर्फ़ +गुवाहाटी +बेच +नाटकीय +शोर +पुराणों +मरीज +वाजपेयी +तिवारी +रही। +ब्रेक +फैले +विन्यास +भाप +थोड़े +सर्वोत्तम +शशि +पार्वती +रचनाकाल +अदा +गयीं +पुर्णिया +बॉन्ड +बिन +मोंटे +नाक +दीक्षित +जिनमे +अवलोकन +नस्ल +डेनमार्क +वरुण +विभक्त +सैकड़ों +अनुभूति +पंजीकृत +मतभेद +कॉमेडी +कलात्मक +निकाय +तरफ़ +आणि +साथियों +गुलाब +झिल्ली +सोना +संश्लेषण +इलाकों +पण्डित +आया। +रेसिंग +खपत +टेलीफोन +पड़ते +दिलीप +ई० +एकादशी +प्रतिबंधित +फलों +साइड +उपासना +खोटे +प्रिक्स +एचआईवी +आमंत्रित +फार्म +इसपर +रेंज +१९९९ +प्रयाग +मंगोल +शासित +रद्द +अजय +भाजपा +आईएसबीएन +सुमित +एवम् +रजिस्टर +विकीस्रोत +इंदौर +बोइंग +अमृतसर +मकान +पारिस्थितिकी +मैड्रिड +समन्वय +अन्ना +लोहा +कम्युनिस्ट +गण +अवसरों +ब्यूरो +चूँकि +खुली +तन्त्र +राजपूत +समझते +बिहारी +वैष्णव +चैंपियनशिप +प्रतिकूल +सिंड्रोम +बंबई +अमृतपुर +ख्याति +पुर्तगाल +क्यूँ +घ +नारी +अनुभाग +मैरी +गर्भाशय +सर्व +पूर्ववर्ती +चतुर्थ +इमारतों +रेजिस्ट्रेशन +प्रभु +अस्वीकार +साक्ष्य +वॉ +बढ़कर +इनकार +सांस +प्रतिवर्ष +भाषी +बढा +मूत्र +अरारिया +निकलती +क्रिटिक्स +धारक +उपयोगिता +त्योहार +समेत +प्रतिरक्षा +बटन +समर्थ +दा +नगरी +तेज़ +भूतपूर्व +देखता +दमन +अनुचित +श्रीवास्तव +हट +प्रशंसकों +भंडा +तथ्यों +दस्तावेज +ऑपरेटिंग +कोशिकाएं +वाणिज्य +पोषक +धीमी +वियतनाम +स्कॉट +रहीं +घाव +प्रावधान +१९९२ +बैक +श्रीराम +मुकाबला +स्टेट्स +पादप +गणतंत्र +योजनाओं +रोजर +हार्मोन +उत्पादक +टेक्सास +बेहतरीन +फ़्रांसिसी +राजस्थानी +लगाते +बीटा +मान्य +उद्धरण +एज +उद्घाटन +पूर्वोत्तर +हार्डी +यहा +शैलियों +ऋग्वेद +तमाम +बेन +सुभाष +प्रशिक्षित +दुबारा +भीतरी +प्रिंस +हड्डी +मल्ली +बेचने +महत्त्व +आक्रामक +कार्यकर्ता +कटौती +सोमवार +गिर्द +शुरूआती +तिहाई +खरीदने +इट +बिजनेस +असंभव +डिज़्नी +जानकी +ली। +तें +बने। +खेले +दादा +पृथ्वीराज +सांख्यिकी +हुईं +केविन +बनारस +रोशनी +आरती +पीछा +स्थानांतरण +रिश्ते +बर्तन +परिस्थिति +बोले +राष्ट्रीयता +बलि +इंजीनियर +प्रमेय +बुक्स +उनपर +छंद +गुंजन +टॉवर +शाब्दिक +स्वप्न +सुधारने +यूरो +अवध +तत्त्व +निधि +ललित +भांति +विमानों +जलप्रपात +चाहती +आंकड़ों +तेज़ी +मैनेजमेंट +मैट्रिक्स +राजभाषा +आयाम +गुड +पाली +सनहौला +पारस्परिक +जंग +पिक्चर्स +इनको +आस्था +गुलाबी +आजाद +टेक +ऊंचा +एतमादपुर +ब्लोक +प्रतिनिधियों +स्टेशनों +हालत +१९९१ +अटलांटिक +ऊँचे +वेबसाईट +पत्ते +आलू +इन्द्र +परिकल्पना +सुनने +गुलशन +हज़ार +कम्प्यूटिंग +नियुक्ति +पहुँचा +विशेषताएं +आयात +खुदरा +लैंड +मग +महा +फ़िर +अनुयायी +काफलीगैर +डाउन +ओबामा +कैद +सूजन +उपदेश +विवेचन +मोटा +नारंगी +धर्मों +कुमारी +बंदी +ख़त्म +अल्प +कोटा +चीजों +पहाड़ियों +८० +सर्किट +स्रोतहीन +दुकान +हंस +सैद्धांतिक +किरन +देखें। +तलवार +सबके +ब्रदर्स +दोषी +टेलर +बॉल +कटाई +वाद +पक्षों +फ्रैंक +नगरों +वाहक +विश्वसनीय +समस्याएं +पत्थरों +कार्टून +जि +बीसवीं +तिब्बती +गो +भेंट +जगहों +निष्पादन +विक्रेता +खगोल +रोज +कसम +स्मरण +क्रोध +कॉमिक्स +सूर्यवंशी +पोप +भेजे +्य +किरौली +सख्त +ग्रीष्मकालीन +विल्सन +सुदूर +ढांचे +जगन्नाथ +ड्राइवर +गांवों +कश्मीरी +स्वीडिश +वशिष्ठ +पीड़ा +कहकर +नैतिकता +वस्तुत +औषधीय +मैट +ज्योति +नगला +महापौर +गठित +प्रदाता +श् +आर्ट्स +हटाना +ऊष्मा +सकने +मरने +ग्रीस +मिश्रा +हमसे +आपसे +क्वीन +गिनती +शिल्प +मनोनीत +एकड़ +रोकथाम +हितों +आशू +अधिकृत +इर्द +सांता +खुदाई +स्टीफन +विश्वकोश +लायक +विश्वनाथ +गीतकार +मुमताज़ +रूचि +इराक +लम्बा +ग़ैर +वॉशिंगटन +आपसी +भूमिगत +भरपूर +रावण +वन्य +सौरभ +जुड़ +विद्युत् +अद्यतन +जीएसएम +मैकमोहन +सेतु +दूरदर्शन +संवैधानिक +जीवाश्म +डबल +हानिकारक +दर्पण +पूजन +विलयन +िया +लता +उपहार +क़ानून +थिएटर +परिचालन +एकीकरण +प्लेट +हार्डवेयर +समावेश +संचिका +अपशिष्ट +मनमोहन +फाइबर +भारतीयों +दुसरे +आंखों +संस्कृतियों +यंग +सदियों +मत्स्य +युक्ति +फ्रांसिस्को +बर्लिन +लौटने +मेहता +क्षण +पाश्चात्य +गामा +कैमरा +ताजमहल +सर्च +बना। +तल्ली +साधनों +पहचाना +राजा। +मेरठ +जिसको +मधु +रिश्ता +धूल +गायब +मोर +सीरीज़ +इति +सें +सामुदायिक +अनुदान +ड्रम +बडा +कालिदास +ब्रूस +क्षय +मातृवंश +ट्रिपल +प्रगतिशील +गोस्वामी +शनिवार +हल्का +हिन्दुओं +फैली +विष +गर्भावस्था +विस्तारित +मिमी +बा +डेल्टा +आँखों +दीर्घ +गंतव्य +गणितज्ञ +बिली +बल्लेबाज +क्लोराइड +बालों +मैनचेस्टर +यु +निर्णायक +इंगित +मयुर +साप्ताहिक +वैशाली +पूर्णतया +बच्चा +अक्ष +भविष्यवाणी +भ्रमण +हांगकांग +ब्लेक +रेस्तरां +कृपा +परेशान +विकासशील +मांसपेशियों +गोविन्द +प्राकृत +कथाएँ +गुलाम +व्यस्त +मार्गदर्शन +कोंच +कट +प्रतिस्थापित +वैभव +पहने +पाठकों +बातकरें +डॉग +विकिमीडिया +बेदी +पोशाक +चंद्रमा +छिद्र +इमारतें +माउंट +सिफारिश +होगन +उज्जैन +समर्थित +ब्रह्माण्ड +रसूल +श्लोक +राहत +आखिर +एम् +दाल +पकड़ने +मुँह +उत्साह +गर्दन +तुलनात्मक +काटने +पाक +महारानी +ग्रंथि +जरुर +यूरोपियन +आत्महत्या +शर्त +चुम्बकीय +सम्प्रदाय +नवीनतम +हीरो +मशीनों +जयंती +मिथुन +उद्देश्यों +सामयिक +अकेला +परिवेश +मोड +लवण +चिली +रखरखाव +बोलचाल +अभिलेख +चाँद +लें। +सेनाओं +अखबार +दिखा +रूपरेखा +भास्कर +समाधि +विंडोज +बनाया। +भयंकर +अमृत +अरुणा +ऊंचे +खेर +दोबारा +बाध्य +लगी। +नागर +उपन्यासों +हीन्दी +नाट्य +जनक +नमूना +टीमों +आउटपुट +जोस +कोरियाई +मरम्मत +डाक्टर +सूरा +कष्ट +परीक्षणों +बाएं +भरने +वेन +केस +महिलाएं +लुप्त +फ्रेम +द्विवेदी +असरानी +शोषण +नियमितता +इंसान +पद्य +वायुमंडल +पोल +विलुप्त +अपूर्ण +बेचा +लिनक्स +कडी +सतीश +बहरहाल +आयी +हिन्दु +मल +बताने +श्रीनगर +लड़ने +टोक्यो +ऊँची +पर्ल +पितृवंश +नी +दीर्घा +धार +मंदी +फ्री +घंटा +दोपहर +इंस्टिट्यूट +गुर्दे +एचटीएमएल +रजत +अवकाश +सीबीएस +पाना +होती। +फेसबुक +भगवानपुर +पतली +सीट +मोड़ +मक्का +स्पेक्ट्रम +संरचनाओं +इसमे +बुध +ब्लूज़ +अवसाद +अफगानिस्तान +पंजीकरण +जरुरत +अवरोध +ब्राउज़र +टाइगर +विनिर्माण +जालघर +विज्ञापनों +बॉट +ग्यारह +मुजफ्फरपुर +गिनी +परी +मिलेगा +कस्बे +भाषाई +बारी +माँग +गैलरी +मिलन +शुक्र +आर्मेनिया +इंस्टीट्यूट +आत्मकथा +सदस्योंको +प्रतिपादन +टर्मिनल +रहेगा। +पेड़ों +मिली। +कमीशन +योनि +फसलों +गतिशील +भी। +संचरण +प्रभुत्व +उपक्रम +समुचित +दक्षता +द्रविड़ +बन्द +दिखता +मध्यप्रदेश +सारांश +भीम +अस्तित्वहीन +हथियारों +खुराक +प्रकारों +तेरा +ताकत +भगवान् +लेक +समकक्ष +देशांतर +ै। +जोसेफ +आज़ाद +सामान्यत +उपभोग +भीष्म +ऊतकों +खिलाफ़ +लोकमान्य +अन +राजू +अस्थि +दरवाजे +राजनेता +आघात +उपमहाद्वीप +प्रख्यात +टोनी +टुल्सका +विफलता +स्टोरी +बैठ +बनना +स्वतः +भाषाविज्ञान +दृढ़ +अर्थात्‌ +शी +पचास +प्रसिद्धि +अपराधी +डाली +हरि +डकोटा +कोहली +प्लेयर +आश्रय +नाग +बिस्मिल +छात्रवृति +मिनेसोटा +लाए +सकें। +चुनावों +ब्रिज +चिंतन +बिगाड +विमर्श +पहुंचे +होंगे। +वैसा +भूख +दिखें +नॉर्थ +अवस्थित +घेरे +स्ट्रोक +सर्बिया +असल +हिन्दुस्तानी +घन +वीज़ा +महोत्सव +घटकों +बढ़ी +करवा +सुनकर +रावल +घट +प्रायद्वीप +स्वाधीनता +विशेषज्ञों +प्रबंधकोने +कैलिन्डर +धनरूआ +डेली +किलो +जाट +अधिकारिक +माहौल +सीटें +पुरातत्व +पीपल +लीटर +अनुकूलन +गेंदबाज़ी +शीह +वायुसेना +सूर्यगढा +उन्होनें +सिंध +इधर +टैंक +पंच +भूमध्य +अफ़्रीकी +डांस +बलिया +एड्स +जनन +जंतु +समझना +ग्रन्थों +सैम +गुरुत्वाकर्षण +कोमल +जायेंगे +थाईलैंड +टेलिविज़न +दायर +ज़िले +त्रिपाठी +प्राचीनतम +विदेशों +करी +पढ़ा +पर्वतीय +नाइट्रोजन +परशुराम +स्वतन्त्रता +चार्ज +मेहनत +फिलिप +पेट्रोलियम +नदियां +पिंड +उत्तरार्ध +लेनदेन +दीर्घकालिक +आयतन +मूलभूत +टनकपुर +डाटाबेस +औरत +नकल +डि +चैंपियन +मोती +होनेवाले +दिमाग +टेक्स्ट +जीवनचरित +मणिपुर +फील्ड +प्रक्षेपण +निकले +खड़गपुर +करन +९१ +प्रदर्शनी +अनुष्ठान +वक्र +संबोधित +शिविर +वास्तविकता +गोआ +मेटल +भगत +सवार +मजदूर +शतक +मानवता +वॉन +बढ़ाया +दानव +सदृश +१९८९ +विभागों +कमाल +बचत +मिर्च +कॉफी +बडे +कीं +फर्स्ट +स्तन +कोने +संसारके +१९७२ +डुमरिया +क् +आवागमन +१९८० +होम्स +संकलित +पत्तियों +सूखे +मुलाकात +लास +सनातन +सामग्रियों +कुत्तों +रोबोट +खैरागढ़ +कर्नल +राखी +आधारभूत +पालीगंज +स्पेशल +संजीव +अग्रवाल +आस्ट्रेलिया +आधी +सूरत +संक्रामक +मुझसे +मुग़ल +वोल्टेज +अणुओं +ज़रा +सील +खनन +समानांतर +बोला +ग्रे +ष +भागवत +रंजीत +मीनार +पूर्णागिरी +बीरबल +गायत्री +जबलपुर +उजागर +सशस्त्र +कोच +प्रश्नों +बुंदेलखंड +बडी +बदलते +पुर +जीवविज्ञान +राह +प्रशंसक +पर्यावरणीय +लड़कियों +स्टोर +संगत +प्रोफ़ेसर +एलिस +हिंद +पूल +भि +९० +भावनात्मक +प्राथमिकता +वाष्प +ओल्ड +आज्ञा +औजार +गैसों +व्हिस्की +रोका +कहती +जहाजों +सशक्त +दिवसीय +उतार +शान्ति +वृक्षों +प्रचुर +प्रसव +७० +संरचनात्मक +फीचर +फॉक्स +देरी +पुरूष +कीबोर्ड +लाइट +शिलालेख +सपना +व्युत्पत्ति +कद +सजीव +लोकतांत्रिक +स्राव +विन्डोज़ +शॉट +चिह्नित +उधार +जेट +चे +युधिष्ठिर +माधव +आसन +संख्याओं +शेख +घूमने +आक्सीजन +राइट +नियत +इतिहासकारों +एनरॉन +रु +पारम्परिक +व् +सर्वथा +वाद्य +आपदा +दरभंगा +जात +१९७१ +लाभदायक +म्यूजिक +दावे +वोल्डेमॉर्ट +भारतवर्ष +जोकर +राणा +कादर +गढ़ +कनालीछीना +मुकेश +जाएं +क्लार्क +बॉबी +सम्पन्न +भूरे +शोधकर्ताओं +पूर्ववत +अहिंसा +बीमार +जूते +फाइल +नारियल +अमरीश +अवतरण +छेद +शर्करा +सेनापति +एक्सेस +वस्तुएं +वादक +दांत +योगी +चोल +परिष्कृत +श्रमिक +नामांकरण +सबको +जिसपर +इलेक्ट्रॉन +महिमा +क्षैतिज +उत्तरदायी +शूटिंग +कारखाने +आरक्षण +आरेख +किए। +रो +यों +घटनाएं +बाइबिल +दम +वार्ड +ज़रूरी +औचित्य +एव +१९७० +तीस +यूनिट +खेलते +डेटाबेस +मामूली +सफर +अध्यक्षता +आदर +कॉर्पोरेशन +चैतन्य +िक +निरपेक्ष +निकोलस +आसमान +विश्राम +वर्जीनिया +अभिनीत +आन +संरक्षक +दाता +तेरी +जॉनसन +अल्कोहल +दिस +दर्शाते +अन्वेषण +लगाई +जीने +टीबी +३०० +उदाहरणार्थ +करण +चंडीगढ़ +शरद +कास्त्रो +सहकारी +छुट्टी +स्थिरता +जोड़ता +कैल्शियम +वुड्स +ित +सपने +इत्यादि। +प्रजा +सेक्स +शुक्रवार +सर्दियों +चीजें +नाव +फर्म +हॉकी +कहां +विमानक्षेत्रों +१९४७ +चढ़ाई +परवर्ती +क्षत्रिय +ब्राह्मणों +कराता +नौबतपुर +आयन +आइ +प्रवर्तन +लिटिल +स्वत +नासा +तंग +रक्षक +ग्रोवर +शिवपुरी +सीडी +गौर +बतौर +कल्प +साधु +इकाइयाँ +पढ़ +दीक्षा +घंटों +करेगी +उदहारण +लीवर +सती +बियर +हार्वर्ड +सहारे +दक्ष +१९९६ +अभिषेक +तुम्हारी +रेगिस्तान +अभयारण्य +चाचा +प्रशासकीय +टावर +अनुकरण +जें +ऊन +फायर +जैसलमेर +कविताएँ +विक्रमादित्य +लड़के +न्यायिक +आपराधिक +निंदा +सेठ +गत +दुर्योधन +गगनचुम्बी +हीरा +१९९५ +वैन +मिशेल +मालुम +जिमी +रिपब्लिकन +चटर्जी +पेपर +बोस्टन +व्यापारियों +शान +सुप्रसिद्ध +सचिन +हु +राजकुमारी +निवारण +विकृत +त्रिपुरा +लेबनान +परेशानी +१९९७ +देवलथल +प्रत्यय +मरीजों +स्‍थान +फतेहपुर +ह्रदय +अध्यापन +लीड्स +औरंगजेब +वस्तुएँ +निवेशकों +सरोवर +एंडी +दिनांक +कंट्री +लीप +गंध +श्रेणियां +आरक्षित +मारुति +प्रशासक +ज़िन्दगी +जन्मस्थान +वॉल +भाइयों +सहकुंड +शेयरों +कवरेज +धाम +कर्ता +वाल्मीकि +संग +सेल्सियस +सलीम +सूक्ष्मदर्शी +यांत्रिकी +इलाका +रियल +पंकज +विशेषताएँ +मकबरा +प्रहार +अजमेर +अभिगमन +केशव +मयूर +धनी +ऑक्साइड +अरुणाचल +उपलब्धता +नजदीकी +इंजीनियरी +डीन +उपनिषद् +जरूर +प्रखण्ड। +ब्रह्मांड +शीत +पहाड़ों +एक्ट +विण्डोज़ +छठी +कश्यप +वार्नर +उ०व० +बुश +१९६० +सन्त +पारसी +खोजने +कुंजी +रोमानिया +इकट्ठा +लय +शस्त्र +फलन +तुलसीदास +आदित्य +जगदीशपुर +नीम +इयर +सामान्यतया +चार्ली +जानेवाले +एजेंसियों +पाटिल +सिगरेट +बरकरार +पाठ्य +साहनी +जोड़कर +शैल +पाचन +लेट +से। +अनावश्यक +गतिविधियाँ +विषयक +शर्तों +असंख्य +याहू +विक्रय +राष्ट्रमंडल +ऑस्ट्रेलियन +बलिदान +उपेक्षा +पाती +गौरी +संचित +मार्केट +सिकंदर +सीरिया +अभिक्रिया +टक्कर +दहन +हैमिल्टन +घोष +समाजशास्त्र +भाग्य +चट्टानों +साझेदारी +पठन +उत्तेजित +अवशोषण +चिकित्सकीय +अपमान +ओजोन +स्तूप +वयस्कों +ट्यूमर +रॉ +इंटरफेस +टेबल +संज्ञानात्मक +सच्चे +कपड़ा +वक़्त +ऐल्बम +मित्रों +बीहता +उदाहरणों +ऑस्कर +पृथक् +घी +अं +सुई +झलक +विराम +फोर्ट +पुरस्कारों +इज़ +एनबीसी +रखा। +सत्येन्द्र +वर्णक्रम +चांदी +वेगास +नें +वषीश्ठ +श्र +बगैर +पुनर्निर्माण +आदान +हिटलर +क्षतिग्रस्त +ज्यों +प्रसंस्करण +सुरंग +शाकाहारी +धनुष +वैचारिक +मधुर +गायिका +प्रोफाइल +प्रतिरोधी +उपज +संवर्धन +चेहरा +बाँध +कोर्स +स्पेनी +परिप्रेक्ष्य +प्रतापगढ़ +महानगर +सुनाई +गद्दी +वास्तु +निर्देशांक +आँखें +व्यतीत +उन्नीसवीं +गिरने +भावों +सांख्यिकीय +आशय +भगवती +साधारणतया +भोज +मुराद +रवी +प्लेस +परंपराओं +हिप +डार्क +चुन +साजन +परिदृश्य +रज़ा +ताइवान +सवारी +देखिये +त्रिकोण +कपड़ों +पद्धतियों +अपनाने +स्त्रोत +खिज़िरसराय +समर +जड़ी +वेदव्यास +१९६५ +चलन +जिव् +सौंप +औपनिवेशिक +चिकित्सीय +ट्रेड +स्वच्छ +बुरे +डैनियल +मंगलवार +पूर्वज +उष्मा +चिकित्सकों +रूपांतरित +जंतुओं +नारद +पैकेज +नागरी +पल +बहुविकल्पी +तथाकथित +कार्यक्षेत्र +पंख +अवॉर्ड +मसौढी +तम्बाकू +लहर +बीमारियों +निरूपण +साइकिल +थीम +क्रान्तिकारी +इंग्लैण्ड +सर्वत्र +जॉर्जिया +शेट्टी +छाप +मलिक +हैमबर्ग +स्वदेशी +सूचक +१९६२ +धारचुला +चर्चिल +रिलायंस +ईस +ती +संकर +विजुअल +उदार +उद्गम +पंचमी +मंजूरी +अनन्त +प्रायोजित +नेट +मालवा +लाई +बगल +धर्मेन्द्र +नाश +फीफा +नगरपालिका +टेप +खुर्द +मार्गों +धमकी +शिवलिंग +प्रासंगिक +धरहरा +मारिया +विवादित +मेक्सिकन +१९८६ +उपायों +दरअसल +सम्पादक +वृत्तचित्र +सिंगल +लुई +विद्यार्थियों +मुद्दा +फैसले +आए। +अलगाव +मिशिगन +धान +भयानक +पिट +दिखाए +ान +चाप +पहनने +विशेषज्ञता +पैट्रिक +इनमे +चर +कुत्ता +निर्वाण +दण्ड +नागरिकता +दुकानों +वर्चुअल +लंका +शॉन +ब्लड +जैक्सन +जलीय +अमास +कड़ियों +अनुसूचित +रेत +गारंटी +दिशाओं +स्टैनफोर्ड +मूलत +डेनियल +परि +सेवक +अमृता +शताब्दियों +जायेगी +दिलचस्पी +नाईट +मॉडलों +हान +स्वायत्त +ज्वर +जवाहरलाल +आगामी +कूद +बुधवार +राक्षस +आयेगा। +इंटर +वांछित +धमनी +सुलभ +बाण +वाई +पुरातात्विक +गौड़ +सामवेद +नाभिक +अध्यापक +समाजवाद +उद्भव +डैनी +चक्रवात +फैलाव +एंटीबायोटिक +चर्चित +जितेन्द्र +उपनिवेश +लास्ट +१९७५ +डाई +गुणा +सूट +इलेक्ट्रॉनिक्स +स्क्वायर +डाले +दुःख +कुंड +सांचे +चंपारण +प्रवास +दुख +अधिवेशन +भरोसा +तप +महामारी +सेब +जेरी +हसन +ऑर्डर +घोड़ा +पासवर्ड +खारिज +ख़ुद +इन्होने +डेविस +सरन +प्लाज्मा +खुलासा +स्कॉटिश +टोरंटो +बेकर +प्रतीक्षा +कराते +क्षमताओं +पांडे +हॉप +कांच +मणि +ऐतरेय +णी +न्यूज +संतुलित +सीला +विरूद्ध +द्वितीयक +ट्रक +भेदभाव +निराला +नजदीक +भाष्य +आयेगा +सहन +उस्ताद +नॉर्वे +बैठा +संस्कारों +घने +गोपनीयता +स्तम्भ +वैमानिक +पंत +भक्तों +सम्भावना +श्वास +ओवेन +जगत् +फायदा +तस्वीरें +रुक +निषेध +नेटवर्किंग +आयरन +मॉडलिंग +१९८४ +चंद +शिमला +कोल +मनोज +बैल +झा +केन्द्रों +केप +एकाधिक +कुरुक्षेत्र +डिएगो +कराना +फिल्मी +ठहराया +जिल्ला +अमीरात +ज़िला +प्रतिस्थापन +मूर्तियों +कूट +साहस +बेबी +हाइब्रिड +पेशी +तिरुपति +सोलह +इयान +डिक्शनरी +ताज +बहुमूल्य +सुगंधित +पैनल +वाटर +नकली +टैक्सी +अस्त्र +बुखार +जानना +उत्परिवर्तन +निमित्त +द्वारका +फिलिप्स +कांगो +आइलैंड +दाढ़ीकेश +आक्साइड +मिल्वौकी +पर्वतों +१९८५ +ढाल +ईस्टर +वर्षो +उधर +बिल्डिंग +ज़ोर +निर्भरता +सिन्धु +अनौपचारिक +यम +योर +नवजात +नियंत्रक +अनुभवों +विज्ञानी +लगाये +वर्णों +स्वतन्त्र +अलौकिक +हीं +बदलता +डालते +चौड़ी +आशीर्वाद +गोद +उपाध्याय +जिनको +स्टर्लिंग +क्यू +सिपाही +मासने +अनुभवी +अपभ्रंश +सलमान +दर्जे +आईसीसी +मेँ +किलोग्राम +इंजनों +खुश +किंग्स +व्यर्थ +प्राप्तकर्ता +सल्तनत +उत +सीख +१००० +अवयवों +जिक्र +दीप +ज्ञानपीठ +कोयले +्र +संदिग्ध +नम +परमाणुओं +मछलियों +मार्टिना +स्कैन +मादक +अधिवर्ष +महान् +लेखांकन +आजीवन +बेला +बाली +दाहिने +उठ +भूरा +कोस्ट +यंत्रों +दलित +पर्याय +प्रस्थान +रेखाओं +ईस्वी +पालतू +गिरा +बरौनी +१९९४ +प्लग +दोहरी +एडम्स +अजीत +सावधानी +थ्री +आशंका +सिल्वर +न्यूयार्क +रोमांस +डॉट +कॉपी +बाप +ईंट +गर्भवती +लाला +घूर्णन +जया +यशवंतपुर +पागल +जागरूकता +कंठ +आईटी +पत्तों +समर्थकों +टूल +राउंड +अन्‍य +ग्रिड +दंत +हिंसक +तार्किक +विशुद्ध +बैठने +मुद्रण +सकती। +पहुंचाने +कंधे +परिश्रम +खोलने +वृत्तांत +सिस्टम्स +धरातल +सांचा +संवेदनशीलता +जिंदगी +पूर्णतः +पुरस्कृत +सराहना +अन्न +मीठा +संतों +डीसी +एंड्रयू +़ +बृहदारण्यक +टुकड़ों +रिजर्व +खंडन +उपभोक्ताओं +टिम +नागार्जुन +श्रवण +प्रविष्टियों +कीटों +रेसलिंग +मैदानों +अभिनव +एनिमेटेड +दीन +बारिश +मॉल +डेथ +क्रान्ति +छोड़ा +पुण्य +प्रतियोगिताओं +देह +माइक्रोफोन +मनाने +किम +हेल्थ +अभिव्यक्त +दस्तावेजों +बेरी +अपहरण +टोपी +बाजारों +संग्रहित +देखो +बहने +भली +चतुर्वेदी +विघटन +रियासत +भवनों +जायेगा। +छठे +अपर्याप्त +वस्तुतः +कार्बोहाइड्रेट +इंजेक्शन +नायर +विद्रोही +बैटमैन +गोल्फ +प्रतिज्ञा +जरा +पीस +बदलती +खरीदा +इंटरनैशनल +झुकाव +लाना +उत्थान +सुसज्जित +अर्चना +ओं +लोड +कमांडर +१९८२ +विद्यालयों +व्याप्त +आतंक +अनियमित +विंग +चंद्रशेखर +जाहिर +त्र +काटकर +गिल +इवान +एंटी +जाता। +प्रदीप +वकालत +परजीवी +प्रणालियां +अहम +केले +चन्द्रगुप्त +इक्विटी +दोस्तों +विद्यापीठ +समर्पण +जिल +तोड़ने +फिलाडेल्फिया +पंचायत +चिड़ियाघर +नर्मदा +विनियमन +परम्परागत +लॉजिक +बधाई +टेक्नोलॉजी +थाई +मापने +सोशल +७५ +फॉण्ट +चित्रकूट +प्राइवेट +मराठा +तुम्हारा +जमशेदपुर +१९६१ +सावली +भूमिकाओं +चयापचय +अभिन्न +किन +खंडों +एलिजाबेथ +ग्रहणाधिकार +ताजा +निक +उदा +प्रयोजनों +पश्चात्‌ +लेखो +गन +नमस्ते +जोनाथन +गोविंद +ऑटोमोबाइल +गोलाकार +गंभीरता +फिनलैंड +प्रबन्धन +पूर्णविराम +एलेक्स +मनोहर +सौदा +स्टाइल +२०१२ +पीट +सामरिक +रेड्डी +दया +प्रा +वॉल्ट +वादा +दरों +उपन्यासकार +तरंगों +स्पैनिश +बरेली +दोस्ती +विकारों +पंक्तियों +दिखायी +ड्रैगन +चाँदी +यश +विकृति +बेसिक +कामयाब +हल्की +अंडा +वास +आर्मी +कार्तिक +श्रे +ब्रह्मचारी +अर्द्ध +ग्रेड +फिल्मांकन +पूर्वानुमान +साइटों +मैत्री +इज +कलाओं +मुद्रित +मिलर +सुंदरता +युवाओं +विंबलडन +मीले +पाणिनि +सहारनपुर +पिशाच +केंडीबार +मृ +डिवीजन +निकलकर +निभाया +मनी +वक्ता +सिग्नल +कैलाश +वाक्यांश +तुर्क +विशेषण +निशाना +अग्रसर +रैंक +१९५० +खाद +ङ +सीटों +कनेक्शन +पेट्रोल +तु +ग्राफ +रण +कंट्रोल +रत +जुड़वां +पूर्वक +बर्बरता +पेरू +एहसास +व्याख्यान +गिल्ड +न्यूज़ीलैंड +कमान +पुत्रों +फ्रांसिस +पुजारी +भरतपुर +कुवैत +मापा +खाई +थकान +रिक्त +अनुमोदन +लेडी +बाएँ +शोथ +अभिप्राय +युवक +स्टेम +नीलम +पीरपैंती +प्रतियां +बहाव +बहार +उत् +अरविन्द +आराधना +मंगोलिया +ध्वन्यात्मक +फ़ेडरर +एयरपोर्ट +बाबर +टेरियर +क्रमिक +विषम +१९९३ +चालित +स्थाई +शीतल +सज़ा +अनुपस्थिति +बफ़ेलो +होस्ट +क्लान +जाएंगे +ऊर्ध्वाधर +द्रौपदी +सूप +रुपया +१९४८ +मीना +शेक्सपियर +बेकार +टैगोर +किताबें +प्रविष्ट +सौंपा +चा +हिंदुओं +ऑब्जेक्ट +अवशोषित +सातवीं +पिन +अयस्क +हाइकु +संस्थाएं +निकासी +भीषण +सल्फेट +बीघा +निपटने +नाते +बाला +रिक +समलैंगिक +आपातकालीन +उष्ण +ईस्टवुड +रचनाएं +बरसात +अमित +यजुर्वेद +प्रशा +संपदा +व्यंजनों +रॉकेट +चट्टान +जार्ज +यहूदियों +विजयनगर +अल्फा +उत्तेजना +प्रायोगिक +अर्थों +गेज +दस्तावेज़ +मानकीकरण +१९७७ +पैक +टेरी +उल्लिखित +काच +परास्त +स्वीकार्य +रचनाकार +अलंकृत +शपथ +अंगूर +अग्रिम +वंचित +कपास +पाण्डवों +दानापुर +घोर +कामना +बह +धोखा +नं +प्रतियोगी +१९६७ +ज़्यादातर +जला +अनुशासन +मसाला +अंडरटेकर +दूरस्थ +सेठी +उसमे +दिलाने +मुक्केबाजी +संस्कृतनिष्ठ +ग्रा +कोकेन +जेरिको +ठंडे +प्रोडक्शन +गर्ल +विराट +गेंदबाजी +पैन +जज +कराची +महानगरीय +स्टाफ +मजदूरों +एनीमेशन +शाखाएँ +वाइन +१९५६ +एंव +वीर्य +सकते। +तलाई +परिपक्व +डेल +अवस्थाओं +सर्प +उन्मुख +भूभाग +युद्धों +रूढ़िवादी +नाथनगर +नामके +लॉस्ट +कॉट +नियामक +वहन +कलम +सम्राट् +परिपूर्ण +इश्क +ड्रीम +कब्र +मोम +अल्बर्ट +दूरबीन +उदर +कानूनों +जवान +इन्हे +सौदे +गान +दामोदर +बेलारूस +श्रेण +दिख +दही +विजयी +घोल +चालीस +मध्ययुगीन +पेंगुइन +समायोजित +मिनी +पीसी +फ़्रांसीसी +सीईओ +भजन +आदत +लिखकर +१९६८ +परमेश्वर +एरिया +कमर +रेशम +मिसाइल +जेन +मोटर्स +उग्र +शैव +डालता +यूनिवर्सल +पिनांग +फ्लैश +विजेताओं +१९८८ +स्वरों +बैंगनी +स्विच +फेफड़ों +सच्चाई +चरित +निकटवर्ती +इंद्र +निवेशक +सिकंदराबाद +पूंछ +समाहित +चित्त +फिट +खुसरो +सार्वभौमिक +खाया +स्थानिक +चिट्ठा +लग्गा +समझे +उपसर्ग +भोग +साइन +क्रीम +पाकर +बोलियों +सका। +१९७३ +सिद्धि +गुलज़ार +आलोचनात्मक +मिलाया +शोभा +ऐनी +दायरे +गईं। +जाएगी। +वाल्व +वैली +रामचंद्र +संध्या +क्रय +सम्बद्ध +जमाने +सहस्रनामन +ध्वस्त +किरणों +कै +आएगा +एस्टन +सोचना +अनुयायियों +जवाहर +मॅट +निभाने +का। +क्रोएशिया +कीर्ति +कल्चर +चालु +ईथेन +इरादा +न्यास +वृंदावन +हिम +गेट्स +ज़ी +वृद्धी +परीचय +डेबिट +कार्निवल +सकी +नालंदा +यो +परेश +कालांतर +मुखिया +डेड +डब्लू +सांख्य +फ्रैंकफर्ट +अजीब +वृत्ति +एफ़ +अबतक +रूट +हिस्सेदारी +आवेश +रू +अंतरण +वॉकर +भवानी +पत्ती +धवन +लाभकारी +मैगज़ीन +ओपेरा +निकलते +परिधि +विलक्षण +बताती +शिक्षित +१९५४ +विद +लेफ्टिनेंट +उल्लेखनीयता +जोली +रतन +डालर +उड़िया +अनुपालन +क्रिस्टोफर +केदारनाथ +डायोड +तराई +गुरारू +प्रतिपादित +धुरी +प्रतिबिंबित +अंग्रेज़ +स्टेज +खलनायक +सुप्रीम +राष्ट्रवादी +स्विस +कैथरीन +अपोल्लोन +हिल्स +प्रवर्तक +रबर +जोड़ों +बॉम्बे +विवादों +वेस्टर्न +मध्यवर्ती +मालिश +दीवाना +गुरुवार +दर्शाती +गतिविधियां +मुख्यधारा +ऋषियों +खिलाडी +औसतन +फ्रेडरिक +पंचम +सूखी +चौड़ा +विधियाँ +१९८७ +बेंजामिन +गली +हफ्ते +डीप +नलिका +पिंक +आईपी +साउंडट्रैक +दिनकर +एमटीवी +अंकन +क्रूज़ +कैफीन +बल्लेबाजी +देसाई +ऑप्टिकल +विद्वान् +हेड +लेंगे। +शिवा +बॉण्ड +कुशलता +क्वांटम +अनिश्चित +कन्नड +विचित्र +रग्बी +रिव्यू +प्रपत्र +निष्पक्षता +आर्कटिक +समस्याएँ +प्रयोगात्मक +जुडना +वाल +ज़िम्बाब्वे +तलाक +व्योम +बिक्रम +अमीनो +प्रतिस्पर्धी +श्रीश +विश्वव्यापी +ग्राउंड +पॉवर +्ड +बहुतायत +मौसमी +उतर +तैनात +चित्रकारी +इंटरफ़ेस +खगोलशास्त्र +गुहा +अपराधों +पाउडर +नॉन +टिप्पणियां +डू +राजन +मेघालय +समृद्धि +सीमेंट +कथाकार +गौराडीह +कतिपय +डगलस +असमिया +आदिम +हज़ारों +मीर +हड़ताल +ज्ञानसे +पोर्टलैंड +्रेणी +संकाय +दर्शाने +अल्लाह +बिल्ली +श्रमिकों +अल्पसंख्यक +मेजबानी +चाइना +ह्रास +फ़ाइलें +गल्फ +राख +औषधियों +१८५७ +आश्चर्यजनक +हाउ +खेतों +विनंत्ती +बढ़े +ग्रीवा +ऋषिकेश +पुनपुन +जटिलता +राज्‍य +लक्ष्यों +डमी +किताबों +जोश +लड़कों +कॉमिक +कैमरून +पूर +हमे +१९८१ +स्पर्धा +दिखाता +कार्यकर्ताओं +वरदान +कराई +अनुकूलित +आचार +गार्ड +सुर +मोर्चा +१९७४ +प्रदत्त +प्रेत +डेवलपमेंट +कार्यात्मक +बालू +पहचानने +आश्रित +रॉबिन +आकस्मिक +कस्बा +मालिकों +उपाध्यक्ष +सिलिकॉन +करेगा। +दूत +संग्रहण +ड्रग +गिरजाघर +मोहब्बत +घूम +चैन +आर्यों +महासचिव +फिलहाल +मेजबान +बसने +१९८३ +पोत +एप्पल +रेणी +मल्होत्रा +चैप्लिन +जीवाणुओं +१९७६ +छाती +ट्विटर +सिकन्दर +बोझ +बैठकर +ऐसें +विस्फोटक +अद्वैत +जीवनकाल +विचलन +कैपिटल +नाटककार +उपवास +बसें +बांटा +मदर +डेस्कटॉप +उन्मूलन +देनी +इच्छुक +नेटस्केप +बैरी +ढाका +ति +तह +एचटीएम +खुफिया +कामों +आतंरिक +सोनिया +स्वम् +ईमान +सार्थक +मेडिसिन +काण्ड +कॉमन्स +अफ़ग़ानिस्तान +शिशुओं +शतरंज +१२४ +गाजियाबाद +सर्दी +स्क्रिप्ट +बैकअप +छद्म +केली +मकर +साधक +मूर्तियां +शिया +सूरी +छाल +अब्राहम +फूड +ञ +पालि +मीमांसा +मीरा +मान्यताओं +कैसा +विनय +जाय। +लेम्बोर्गिनी +इज़रायल +जीनोम +मैक्सिको +एलिज़ाबेथ +नॉट +कंक्रीट +बाधित +यूनिक्स +पाण्डव +स्तनधारी +सिवाय +शारदा +सत्याग्रह +पूर्णत +कठ +बताई +लीड +उत्सर्जित +सुधारों +एंडरसन +उत्कर्षराज +कमला +मैनेजर +डीजल +डेक +शेखर +साईट +संयम +बढ़ाकर +तैत्तिरीय +चमत्कार +कवच +तिल +सप्रू +४०० +सिंधु +सब्जी +पाइप +मैथ्यू +लेग +वादी +काय +नेचर +कागज़ +मंजिल +बेल्ट +प्रोफ़ाइल +गाथा +सीमांत +कीमतों +अंतर्निहित +मुद्राओं +जग +ममता +स्टीवन +शास्त्रों +फोरम +लिए। +विचारक +प्रबंधकोंने +हिंदुस्तान +सिखों +महत्ता +गोदावरी +खुदाबंदपुर +दुबे +सबका +फिक्शन +व्यवसायिक +मरे +चमड़े +कालोनी +सितारों +दुरउपयोग +आयुक्त +नसीरुद्दीन +दाँत +सुलतानगंज +राष्ट्रिय +फतुहा +संग्रामपुर +सोर्स +करेंगे। +सहयोगियों +क्लैप्टन +बीजगणित +प्रांतों +आभासी +दीवान +मानो +गौण +लगाता +डेनिस +सुदृढ़ +एडम +आभास +सदस्योंके +उठता +ल्योन +बंगला +टुन +लिट्टे +नक्काशी +बिंदुओं +हेपेटाइटिस +वामन +जिलाधिकारी +्व +आठवीं +फी +जिन्ना +क्वार्टर +अनवर +विंडोज़ +देखरेख +ऑयल +समजकर +साहित्यकारों +बालकाण्ड +कौटिल्य +जामनगर +अंचल +बिकने +ज्ञानकोषकी +अंगूठी +खींच +एफबीआई +पेस्ट +विडियो +मिलना +लाइनों +भूटान +ट्रेडमार्क +तने +बापकी +अत्याचार +मॉरिसन +मलय +उतने +एंटीबॉडी +मिठाई +१९७९ +कोलेस्ट्रॉल +ेणी +संतुष्ट +बेगम +समझता +पोलिश +फ़ुटबॉल +मीटाकर +तारापुर +धनबाद +एयरलाइन +लाकर +अप्रत्यक्ष +इंकार +लौटे +मानसून +रॉबर्ट्स +फोर्स +चलाते +प्रिंट +ठ +यूनेस्को +धुन +स्टॉप +हर्ष +ऊ +सावित्री +सलाम +फेडरल +जनित +कु +अन्तरिक्ष +विक्टर +इथियोपिया +दुरुपयोग +भारद्वाज +नमः +दांते +शव +सचमुच +मुनिता +चौथाई +सालाना +कब्जे +ओड़िशा +अंतत +संगमरमर +पारिस्थितिक +आरम्भिक +राघव +मैसाचुसेट्स +वीकीपीडीयांके +पुनर्जागरण +मिलक्त +बमबारी +अस्थिर +प्रतीकों +उच्चतर +पतले +अधिकांशतः +चरित्रों +सौन्दर्य +पुरातन +डिज्नी +ड्यूक +कार्यालयों +कमज़ोर +मेट +शेफ़ील्ड +आरएनए +उत्प्रेरक +सेक्शन +संभोग +बास +वापिस +राष्ट्रभाषा +सस्ते +मैदानी +लग्न +भोजपुर +कुण्ड +सघन +फ़ॉर +१९६४ +संस्मरण +फॉर्म +वैद्युत +पाम +परदे +अचल +ग़लती +मंद +बरियारपुर +शुद्धता +परवेज़ +बॉय +जीभ +रोलिंग +बदलना +स्टब +भुवनेश्वर +कोइ +हस्तांतरण +मुकदमे +फैलने +पैरिस +प्रत्यारोपण +अफ़्ग़ानिस्तान +दयाल +कवक +मेमोरियल +एयरबस +इंटेल +फिल्मफेयर +बरोबर +पहुँचे +सावरकर +कुरान +माली +दिखाते +किनारों +निचली +कराती +किस्मों +रहेंगे +रीढ़ +खजुराहो +शियर्र +घात +स्वयंसेवक +मेगावाट +झरने +बाढ +ग्रीष्म +हराकर +ठंडी +गेहूं +ओबेरॉय +फ्रेंकलिन +केंद्रों +शुक्राणु +रूपये +इकाइयां +हटाकर +प्रचारक +रैंकिंग +नीली +क्लाउड +निजामुद्दीन +फर्क +ग्लास +उपजाऊ +गैरी +घुटने +सत्यजित +न्यून +कमजोरी +जोएल +हरीश +जन्मदिन +क्योकि +शिवराज +ख़़ुदा +सिक्कों +पंचांग +मिथिला +१९३० +पेशे +राष्‍ट्रीय +पहना +कॅरियर +प्रतिष्ठान +मालदीव +कलाम +गेहूँ +हुयी +दुष्ट +रांची +टुकड़ा +डाकू +प्रक्रियाएं +सहाय +फ्रंट +निकास +लहसुन +हेलन +डाइऑक्साइड +श्रद्धांजलि +चिप +रोमांटिक +बॉडी +शोक +सितारा +लेनी +आयुर्विज्ञान +फेम +हरित +हीमोग्लोबिन +ब्रायंट +गोला +मानद +कब्ज़ा +व्यू +प्रदर्शनों +डेमोक्रेटिक +फेंक +आंत +समुच्चय +मातृभाषा +महाराणा +रिटर्न +१९५७ +छपाई +उपग्रहों +गोले +जीवंत +रियो +ैं +दृढ़ता +धीमा +गज +यादृच्छिक +विपक्ष +विमानन +कथाएं +चेष्टा +गतिशीलता +लालकुआँ +१५० +दिलचस्प +बैक्टीरिया +पवार +ढांचा +पंप +नूतन +आमन्त्रित +पुस्तिका +चौदह +फोर +सऊदी +सरसों +कैलिफ़ोर्निया +नेल्सन +रकम +६५ +कहा। +नायिका +आभार +अनजाने +एस्टर +एलेन +प्रेरक +जरुरी +वाइल्ड +विशेषाधिकार +नरसिंह +ब्रदर +अधिकता +बर्मी +धाराओं +सिंघल +समीक्षकों +राजदूत +समारोहों +ढेर +सूखा +अर्जेन्टीना +प्लेटो +१९६३ +१९६६ +स्थलाकृति +इरादे +कर्मों +जानेवाली +क्षीण +मरुस्थल +प्रांतीय +स्काई +ऍ +विशिष्टता +एमी +अरबों +इंसुलिन +युवावस्था +कैमरे +नमूनों +जावेद +नक्शे +सु +१९६९ +संकुचन +किय +समीक्षाएं +स्पिन +हवाला +कारावास +शिक्षकों +नाहीं +सर्जन +दाने +उठाते +वरन् +६०० +उठाना +भट्टाचार्य +्ता +डोनाल्ड +संतृप्त +हड्डियों +मिलाने +करनेवाला +निकोबार +दे। +सॉसेज +चेतन +त्रिवेंद्रम +ऐन +करीबी +मासको +पहेली +देशभर +इमेज +मोटाई +सिगार +ऑक्सीकरण +मैनुअल +सूअर +चलना +पड़े। +पर। +पराजय +मंगेशकर +नर्तकी +यज्ञोपवीत +देखिए +द्योतक +आतां +मीठे +भागने +रूपी +परिणत +श्रृंगार +शक्तिपीठ +कुरु +बीजिंग +मुगलों +घटा +सच्चा +वान +पैकेट +चौथान +मॉर्गन +सिवा +इन्टरनेट +वैधानिक +मास्को +भेड़ +रोहिणी +मैरीलैंड +भेजी +मिर्ज़ा +परिशिष्ट +निर्माणाधीन +असे +रॉन +डायरी +द् +संदूक +नक्शा +विराजमान +विकल्पों +प्रधानता +लिपियों +काउण्टी +याचिका +वरीयता +विजू +त्रुटियों +निर्देशिका +चूर्ण +समूचे +प्लस +टाइपिंग +लिखें +दोहरे +प्रथाओं +निर्मल +रस्सी +बेखम +ण्ड +बजाया +मुलायम +हमीरपुर +बंधक +प्रतिरक्षी +आपरेशन +निसान +नरम +वॉल्यूम +ख्याल +क्रैमलिन +इट्स +थ्योरी +शेयरधारकों +सुमीत +अंदरूनी +लवी +माधुरी +खातों +गाड़ियों +सजावट +निपटान +खोलकर +जन्मा +पीएच +अभिनेताओं +चावला +प्रेमिका +स्विट्जरलैंड +ब्राउजर +मोदी +शेरशाह +नमी +चालुक्य +सूफी +उचाई +कोलम्बिया +सू +उठाकर +ग़ज़ल +क्षरण +ग़लत +खरीदारी +दुल्हन +शम्मी +निष्ठा +प्रविष्टि +साम्यवादी +रहेगी +अनोखा +स्तुति +उपलब्धियों +परियोजनाएं +गद्यकार +स्विफ्ट +इंडीज +लौकिक +कोशों +प्रिया +शिष्यों +निकली +बाँटने +टकराव +मौजूदगी +निरन्तर +आकाशवाणी +उल +चीफ +सुविधाजनक +यादगार +समाचारपत्र +म्युज़िक +सूचनाओं +जमालपुर +रोकता +लक्षित +दौलत +स्पेंसर +लालू +पिच +आसवन +ज्वार +पाषाण +संयोजित +अरे +ईथरनेट +मय +आखिरकार +एथेंस +लड़का +धूम +निर्देशों +आहे +प्रयोगकर्ता +झीलों +ज्वाला +नागालैंड +आपत्ति +कांस्य +ख़राब +करनेवाली +विगत +ार्ता +फेडरेशन +वैसी +युनुस +वस्त्रों +श्रद्धालु +अदृश्य +सामर्थ्य +६३ +हार्दिक +मानदंड +बौना +सुनवाई +शॉपिंग +बराबरी +सि +पलायन +लाइसेंसिंग +अञ्चल +जगदीप +गोत्र +देहांत +कार्टर +प्रतिबन्ध +शैतान +फांसी +रीड +बोतल +गोविन्दा +सामंजस्य +फर्श +फिल +यूएसए +गाते +उपक्षेत्र +एंग्लो +तुमने +बुगु +निर्वाह +बताए +दूरदर्शी +धोखाधड़ी +संचालक +तकरीबन +आमिर +स्टारबक्स +जड़ें +रूम +टेल +घोड़ों +नरसंहार +प्रीति +अश्लील +कलश +कैलगरी +८५ +घूमते +प्रवक्ता +वूल्वरिन +अप्रत्याशित +आंकड़ा +ग्रीनहाउस +फेस्टिवल +अनूदित +सर्वे +चेन +छवियों +अधिकाधिक +मिटा +पिरामिड +अग्र +चाणक्य +प्रक्षेपास्त्र +१९७८ +विक +टंडन +मैनहटन +कैच +मौन +टमाटर +सांद्रता +इस्तीफा +करवाने +समीक्षक +फारस +वज़न +प्रवृत्तियों +लुइस +उत्तीर्ण +राँची +वनस्पतियों +अल्फ़ा +रीडर +गेंदबाज +नकद +क्रिश्चियन +राजेंद्र +ऐल्कोहॉल +कच्चा +असोसिएशन +लैंग्वेज +मसाले +ज़रूर +मंडी +सुमन +सनी +कर्मियों +साइबेरिया +कंपन +आवर्त +रुधिर +गढ़ी +चिकन +स्नेह +दत्ता +धर्मग्रन्थ +जौनपुर +मुरादाबाद +पर्वतमाला +लौटा +लाये +गोपी +दाएं +पुनर्जीवित +आगम +प्रतिक्रियाओं +हीरे +तीर +भ्रष्ट +गर्भाधान +परेड +टेलीग्राफ +ऐक्शन +वीरता +आर्क +इफ़्तेख़ार +टार्ज़न +प्रतिलिपि +डेढ़ +सम्पत्ति +गर्व +मदुगु +माघ +मूर्तियाँ +छन्द +कठिनाइयों +अभियानों +तया +चांद +कौषीतकि +वास्तुकार +पडता +मज़बूत +कार्यान्वित +क्लाइंट +पूरब +साइमन +क्षतिपूर्ति +माध्यमों +स्केल +उत्तरदायित्व +पतला +पीटर्सबर्ग +नौका +पटल +समझाने +मिसौरी +आण्विक +एस्पिरिन +म०ब० +जोन +कुक +बाईं +ध्येय +ब्लेड +कृत्य +गार्सिया +तीर्थंकर +सम्मुख +चाहीये +मार्केटिंग +रोमांचक +सहानुभूति +वायरलेस +घृणा +महाद्वीपीय +उर्मिला +बसंत +दवाएं +पकाने +नन्दा +अलवर +निराशा +छिपा +तपेदिक +आदिवासियों +अनुवादित +सातवें +सिक्का +संवत् +सावन +कार्पोरेशन +उर्वरक +राही +ओलिवर +पांचवें +झीलें +डेविल +खां +अन्तरराष्ट्रीय +ब्राह्मी +कांड +जू +गाँवों +भैरव +वीकली +टुडे +बेसिन +बाघों +निरूपित +शाप +मन्त्री +कुंडली +अथ +राष्ट्रगान +आणविक +दांतों +वैश्वीकरण +कहें +शैवाल +सिलसिला +कैरी +१९५५ +काबुल +मोटरसाइकिल +विवश +फ़ूड +अरोड़ा +गिरोह +पते +झरना +अनुमोदित +मांडूक्य +कडियां +मजाक +जरी +विकीपीडिया +होत +जमैका +स्पष्टीकरण +पाद +जरूरतों +एम्पायर +हस्त +संहिताओं +लड्डू +मध्यकाल +वीकी +देवगन +चित्रआकार +विदिशा +कॉफ़ी +सेंचुरी +होते। +मित्रता +कठोरता +वज़ीर +रूपक +अश्वेत +राज्यसभा +आभूषण +चैम्पियन +उपरान्त +लार्ड +नोबल +प्रविष्टियां +बस्तियों +िए +नानक +बर्ड +पड़ेगा +लिंकन +बहाल +९६ +बंदूक +रेट +अयोध्याकाण्ड +महाप्रभु +ग्राहम +नल +डार्विन +ग्रेटर +कारखानों +वाट +सोचने +हिम्मत +बढाने +लेबर +गिना +पूर्वजों +बेचे +हरिवंश +श्वेताश्वतर +माइक्रो +सीनेट +पु +दिए। +नकदी +ब्रॉडबैंड +फ्रेमवर्क +दाग +ँ +ग्लूकोज +आश्वासन +दरगाह +बीवी +किस्में +अभिकल्पना +इन्दिरा +रामकृष्ण +शेन +वार् +पॉइंट +झांसी +चेल्सी +वाइस +महानतम +विश्वसनीयता +चूना +डिस्प्ले +प्रकोप +सदाबहार +लोहिया +मीनाक्षी +र्ता +हावर्ड +इस्लामिक +कौशिक +भुजा +पहलवान +जादुई +अर्थशास्त्री +मनमौजी +शायर +डिजाइनर +समयावधि +सपनों +मर्यादा +रेकी +दरवाजा +उत्त +बारूद +हे। +कुर्सी +जन्मजात +लूट +नियोजित +नियोजन +तेरह +हिंगू +मैडोना +्म +सोमनाथ +पीपुल्स +मुद्रास्फीति +बजाने +काँच +तैराकी +साबुन +अभ्यारण्य +बढ़ाते +तन +उ०प० +महासभा +अहंकार +मांसपेशी +निर्वात +खतरों +जाओ +हैपलोग्रुप +हैवीवेट +आरोपों +सितारे +विनियमित +सब्जियों +शीतकालीन +पार्टियों +शिला +रसवात्सल्य +पश्च +चॅक +लड़ाकू +तुझे +रॉस +क्लोरीन +विषाक्तता +मानों +वाक्यों +प्रतियों +उल्टी +हैरिस +निकालना +अक्षम +सिंधी +विशेषत +आस्ट्रिया +अवगत +साधारणत +मार्क्स +चीता +व्यवसायों +डालना +क्षितिज +पालिका +उल्टा +कारखाना +सैयद +कमेटी +भला +फेयर +फ्लू +रामभद्राचार्य +स्प्रिंगस्टीन +पिस्टन +संदर्भों +जनसँख्या +आनुवांशिक +उषा +ज़रिए +सीमाएं +घर्षण +प्रौद्योगिकियों +दिखती +मतों +लत +बैले +एक्यूपंक्चर +फोटोग्राफर +क्रिकेटर +अनीता +इण्डिक +आधिपत्य +सतही +गुफाओं +प्रतीकात्मक +नशीली +शुक्ला +शेंगेन +फास्ट +बुल्गारिया +महंगे +सनम +नज़रिया +हेलो +माथुर +सेवाएँ +रिपब्लिक +सेंसर +सर्कल +बिज़नेस +सेकेंड +असत्यापित +कैनेडी +दुर्भाग्य +विनायक +कारगर +प्रस्तावना +अरस्तू +बताये +गृहयुद्ध +तर +शीट +गिरफ्तारी +वार्मिंग +इसीलिये +महासागरीय +खनिजों +पेरी +जटिलताओं +जीती +लॉरेंस +पूर् +साठ +सूडान +एबीसी +संस्थाएँ +सिएटल +आख्यान +बोल्ट +खानों +यीशु +परिलक्षित +अभिमन्यु +दैत्य +पॉलिन +निकाली +राष्ट्रवाद +खोजा +साक्षी +पारदर्शी +७२ +जाएँगे। +फुलवारीशरीफ़ +वैवाहिक +जुलती +सेंटीमीटर +ईश +नाभि +रेशे +संकीर्ण +नेताजी +टीके +एड्रेस +विश्‍व +चार्टर +बीना +मधुबनी +पियानो +हेक्टेयर +मंगलौर +फलत +सीने +संभाल +अलास्का +स्पाइवेयर +सुलोचना +नीलगिरी +तैसें +उभरा +राजकोट +मिलीग्राम +फाइलें +हिब्रू +बैग +आटा +होतीं +शंख +मजबूती +सीना +उनमे +आज़मी +अभिलेखों +रोचेस्टर +पुष्ट +दाहिनी +क़रीब +कार्लोस +जादूगर +मैनें +अवरुद्ध +झ +सस्ता +लैंस +टैक्स +बैड +इशारा +पढ़ना +विलायक +ज्यामितीय +एनी +पत्तियाँ +बहामास +पढ़े +कारें +प्ले +चश्मे +प्रतिकृति +झंडा +उभरते +स्टेनली +डेव +बेनोइट +वीवरण +निकालकर +तदनुसार +बुल +अवशेषों +कच्छ +बताना +एंटरटेनमेंट +राज्यमंत्री +मायने +परख +बराक +मिले। +ढाई +प्रतिफल +क्रियाएँ +स्थूल +बसु +आकलनकर्ता +गुट +अथर्ववेद +संस +केट +टीमें +सैंडविच +लेखिका +कैबिनेट +जुर्माना +मारी +मिटाने +परवरदिगार +अंदाज़ +मूल्यवान +लिखता +संचय +साउंड +युवराज +विकिक्वेट +स्कूली +नशे +प्रयोक्ताओं +पापों +पित्त +बहल +विकलांग +डूब +किंगफिशर +कार्यक्षमता +टेड +वगैरह +डाउनटाउन +अपूर्व +कलन +थाली +साढ़े +पीली +कृष्णन +९९ +प्रोसेसर +एमआईटी +तंतु +राजेन्द्रनाथ +छीन +स्टैंड +मुरलीधरन +कंप्यूटिंग +सॉफ़्टवेयर +चुप +एसी +प्रोटोटाइप +चुनने +राजी +अंडर +सुविधाएँ +शरत +हरेक +मु +विमानसेवा +पड़ी। +मूर्तिकला +जुडी +संविदा +बाय +बढ़ाता +रुख +लोकगीत +समायोजन +अमेरिकियों +कैन +जीप +नक़ल +तेथ +श्रृंखलाओं +ज़माने +मशीनी +एक्सरे +आह्वान +अलाउद्दीन +प्रत्याशी +बिन्दू +रहस्यमय +रेखाएँ +पिया +पत्रकारों +प्रतिभूति +उमर +स्वच्छता +घनश्याम +विषाक्त +दबाने +अध +जोड़ते +वायुमंडलीय +ठंड +बर्फ़ +फीसदी +लेआउट +दरिया +क्लबों +छत्रपति +असुरक्षित +नागरकोविल +कार्यो +सौभाग्य +परवाह +महंगा +युगांडा +नवाचार +रामचन्द्र +जुलता +निष्कासन +गर्भगृह +वेदांत +निराश +शोधकर्ता +पड़ोस +मौके +असफलता +गय +जयसिंह +हैदर +संगीतकारों +दीपावली +मूसा +समाजों +मानवाधिकार +जोड़ना +ट्रम्प +एंजाइम +गांधीजी +चुनी +१९३१ +डिवाइस +समझाया +हजरत +प्रमोद +कुशीनगर +बर्मन +गोलार्ध +मोह +पढ़ते +गवाह +मर्सिडीज +आमन्त्रण +कतर +एकाधिकार +टायसन +ऑपरेटर +बलराम +होंगी +आये। +नानी +अलीगंज +जहा +विद्युतीय +जड़ों +अपराधियों +द्वि +जौ +बंदर +बढ़िया +रेसलमेनिया +इलेक्ट्रान +फिलीपींस +प्राप्‍त +क्यूंकि +विकलांगता +जिल्हा +सींग +बछवारा +हावी +गाए +एकेडमी +वाइरस +सवालों +फोटोग्राफी +हाइड्रोकार्बनों +कोबेन +स्वर्गीय +यार +कोशिकीय +बखरी +उतरने +गैलापागोस +विलास +हंगल +आज़ादी +अंशों +सिलेंडर +केन्या +अप्रयुक्त +धर्मनिरपेक्ष +प्रबंधको +ताजिकिस्तान +पुनर्गठन +स्टडी +समा +ीर्षक +दोषों +आईएसओ +कोला +रेलमार्ग +जहाज़ +बहाने +थोक +जानबूझकर +बेकेट +कमाने +खाल +छावनी +डबल्स +पहनते +आल +मनोरंजक +फ्रैंकलिन +भ्रमित +सुज़ुकी +वॉर्स +वर्जित +अनशन +वुड +अपवाह +श्राफ +एवेन्यू +नाप +पर्पल +हुक्म +भूगोलवेत्ता +दबा +उभर +शंघाई +पैकेजिंग +नॉटिंघम +वर् +भूमिकाएं +जनमत +सीखा +हलसी +ग्रैमी +सकेगा +वार्त +१९४० +डैन +कलंकीत +कारन +नहरें +पडा +२५० +दर्रा +ओड़िया +कांफ्रेंस +तिमाही +फिल्टर +ग्राफिक्स +लाइक +रोज़ेज़ +केक +आंदोलनों +ऑ +७६ +गाँठ +सेन्ट्रल +करों +पोजीशन +ट्रांस +अस्पतालों +प्रचारित +सपोर्ट +समितियों +एस्टेट +संकुचित +दिखते +जलन +उत्तराधिकार +प्राध्यापक +सूक्ष्मजैविकी +मिर्जापुर +रैखिक +नैनोट्यूब +वीजा +गुजरती +मालाबार +निगमों +पोरबंदर +ट्वेंटी +नवरातिलोवा +्त +७७ +जासूस +अभूतपूर्व +नवागन्तुकों +वर्मनने +मिसाल +गरीबों +फूट +फ्रेंड्स +फोकस +शत +तैसा +गे +एनिमेशन +मेवाड़ +स्ट्रीम +१९५८ +प्रमुखता +पेशियों +ऋ +जलाशय +चलाता +क्ष +हेमामालिनी +बैंगलोर +सुनते +लैंगिक +सुदर्शन +रमन +नाइट्राइट +टिहरी +कैदी +कस्टम +खरा +चिप्स +अनगिनत +महाकवि +आवश्यकताएं +कमिश्नर +रचा +श्रेणीबद्ध +रवाना +बूटी +वाँ +खिलौना +गर्ल्स +कमांड +चलाना +संसद् +तस्वीरों +प्रतियोगिताएं +शाखाएं +निरूपा +पावन +रसायनों +औषध +वीणा +साजिश +बुजुर्ग +एनालॉग +मकबरे +परीक्षित +धोनी +नबम्बर +प्रबंधित +सैल्मन +आकारों +सवाई +माईस्पेस +किण्वन +आईबीएम +प्लांट +गुजर +शर्ट +ल०व० +विकिसम्मेलन +पंद्रहवीं +मातृ +ीय +भिक्षु +फ़ोटो +अपडेट +दोहरा +क्रेन +बाइबल +पहुँचाने +दाएँ +निःशुल्क +नाइट्रेट +एरनाकुलम +पहुंची +सक्रियता +लियोन +मंडली +लोकपाल +निकायों +आधुनिकता +वसूली +नारा +राना +गॉर्डन +दांव +चन्द्रशेखर +हार्बर +सलाद +मंत्रिमंडल +रसेल +तब्दील +आशिक +विधायक +बची +१९४९ +जैकी +पनीर +वेशभूषा +वेल्श +पसन्द +चुपके +चि +अतरी +परतों +मधुबाला +सांप +पहुंचता +रोकना +पकड़े +१९२० +पीतल +नास्तिक +नासिर +किस्मत +लाइनें +प्रतिबिंब +माफी +मार्क्सवादी +एथिलीन +कोशीश +जगद्गुरु +जीना +वाह +प्रेसीडेंसी +सीनियर +पूर्णता +फिजी +अत्र +होनेवाली +बिड़ला +रिवाज +उपनगर +ईथर +बद्रीनाथ +शीर +ु +रेखाचित्र +महेन्द्र +त्तराखण्ड +सूत +सीढ़ी +भट्ठी +भण्डार +व्यवसायी +सेवानिवृत्त +गुणांक +जामा +शेखावत +८०० +क्रूर +घिरे +फलक +अम्बेडकर +लगन +बिन्दुओं +मुकुट +वेस्टमिंस्टर +इमाम +बर्नार्ड +मृदा +बायें +शासकीय +ख़िताब +षड्यंत्र +रेखीय +स्पीयर्स +जीमेल +डिस्ट्रिक्ट +अल्बानिया +राशियों +लीन +गवाही +जस्टिस +स्पेलिंग +बाँटा +कुश +मकसद +अटल +मेटा +सर्पिल +रास +पंखों +संवेदना +हलचल +संकल्पना +३००० +मक्खन +जॉर्डन +मिथ्या +समीकरणों +फेफड़े +पैतृक +प्लैटिनम +एंथोनी +वीनस +बदली +७०० +पीढ़ियों +सूरीनाम +स्ट्रॉस +क्रियाशील +विक्रेताओं +मोल +लड़ते +रहो +वक्तव्य +उत्पादकता +मॉनिटर +पुरोहित +मालवीय +समझी +रूपांतर +पनामा +प्रतिरोधक +समस्तीपुर +वेधशाला +पीड़ितों +देवदास +अवधारणाओं +फर्ग्यूसन +ग्लेन +चौड़े +फाँसी +आंत्र +त्रि +फेरारी +पदार्थो +शंकु +दादी +पुनरावर्तन +विवरणों +हलके +दरार +मीन +गिरीश +चुनें +निभाता +१९४५ +स्पीड +यथार्थवादी +तोप +किट +चिन +पुकार +मॉडर्न +कड़े +कावेरी +आई। +तूफ़ान +द्योल +पिकनिक +बायर +गिटारवादक +एकांकी +लगाव +सस्ती +खुदा +बढ़ाना +संयंत्रों +निष्पक्ष +अरविंद +पकड़ा +गिने +शहद +मिथक +मून +दीया। +डेविडसन +ग्राफिक +प्रियस +अनिष्पक्ष +कराटे +सुनहरा +सचिवालय +फ़ॉर्मैटिंग +वाल्टर +स्तंभों +आटे +स्मार्ट +मेक +घाटियों +मेसन +अनोखी +सदाशिव +प्रतिजन +रुझान +प्रवीण +कपिल +विधवा +रुकावट +टर्नर +त्रिभुज +मंत्रियों +तत्पश्चात +चूहे +म्हणे +कॉलेजों +उत्कीर्ण +र्षक +घेर +नेपोलियन +सुलझाने +विभिन्‍न +आइस +भित्ति +गला +वैधता +लुकास +उड़ +स्टैंडर्ड +खिलौने +युगों +लिवरपूल +लिप्यन्तरण +खड़ीबोली +पर्दे +शत्रुघन +अग्निहोत्री +वर्चस्व +बहिष्कार +एडवेंचर +यूटोपिया +ऐसीटिलीन +विचरण +कल्पित +मुख्‍य +अपनाई +गंधक +ेश +किशोरावस्था +लेज़र +कैम्प +टाई +तुरन्त +अर्धचालक +मॉरीशस +साँस +संगठनात्मक +बहुवचन +तले +कभार +पुकारा +चाँदनी +१९५९ +जिनपर +नागराज +मोनिका +्तराखण्ड +६४ +सुखद +आवारा +पानदारक +एशियन +चैत्र +कैश +हथेली +नैनो +झूठा +विस्थापन +प्रमाणीकरण +इसराइल +आठवें +सागरीय +प्रजापति +किसने +सभ्यताओं +अर्ल +स्वराज +१९३६ +चन्द +बसाया +महानदी +वर्ड +रिसाव +चम्मच +प्रशिक्षक +रघुनाथ +एमिनेम +सुधा +पंद्रह +काटा +चादर +जैम +निकटता +उमा +भयभीत +फ़ॉर्मूला +शाहजहाँ +इंजीनियरों +वर्दी +ूर्व +आनुवंशिकी +घेरा +हाथियों +रैली +संलयन +आवर्ती +क्रियान्वित +दशहरा +वृद्ध +विरोधियों +बोवी +भूविज्ञान +पो +होय +ऋणात्मक +लाते +अण्डा +सम्बंध +बोट +इटावा +साहसिक +आपातकाल +टायर +साइप्रस +चूहों +विधियां +षक +जोड़ती +त्रिज्या +मनाते +बांड +प्रतिबद्धता +आइसलैंड +उत्तेजक +पैमाना +बांद्रा +गर्भपात +पब्लिशिंग +अन्यत्र +बम्बई +महीन +पूंजीवाद +क्रियान्वयन +संगीतमय +दैट +दाखिला +आवश्यकतानुसार +मेनन +स्प्रिंग +ख़िलाफ़ +शक्तियां +अंतरजाल +यूक्रेन +अस +वर्जिन +मानती +सद्भावना +आंद्रे +वल्लभ +इजरायल +अध्यायों +मजदूरी +उत्तरोत्तर +प्रभात +श्रोताओं +हलन्त +हीरोज़ +कुँवर +अलेक्जेंडर +कराया। +वोल्टता +एवार्ड +गोल्डेन +पनडुब्बी +स्टेरॉयड +सचदेव +ट्रू +सिरों +मारकर +माउंटबेटन +बार्नस्टार +कोका +मन्दिरों +फ़िल्मी +धाराएं +सांप्रदायिक +आत्मसमर्पण +समांतर +प्रीमियम +विनोबा +बहुराष्ट्रीय +डैविल +धागे +दसवीं +बार्कलेज +बिरला +प्रतिमान +कक्षाओं +हैना +अमूर्त +मंज़िल +निरंतरता +निपुण +ढोल +१९४२ +मनोरोग +डेप +यूनीवर्स +डाला। +क्षार +शूट +बेसबॉल +बीएमडब्लू +शौकिया +प्रागैतिहासिक +ारत +मुझ +गुफाएं +वर्क +अनन्य +सुरुचि +छा +बग +कर्क +उठे +हक +प्रशस्ति +कलाई +जयप्रकाश +महीना +चिंतित +दूषित +नियोक्ता +स्वदेश +यत्र +पूछताछ +विस्थापित +खोजों +लाभान्वित +कांट +पहचाने +बॉर्न +प्रवृति +रेजिमेंट +थिंक +ऐश +स्थगित +सीटी +विशेषतः +बुराई +रुद्रप्रयाग +सुषमा +८४ +बनी। +जनजातियों +रेख +अन्याय +संवाददाता +कच्ची +बोलियाँ +एडी +पेंटिंग +जिन्हे +रति +स्टार्च +अबू +पहुंचते +अम्लीय +सैर +बीबी +इंटरटेनमेंट +वानस्पतिक +बेशक +श्लोकों +आपात +नन्द +मेज +तृतीयक +टॉड +प्रसिद्द +रांगेय +कैप्टन +बीन +चाह +बनीं +पोटेंशिअल +असित +सीरम +कैदियों +चुनरी +ज्येष्ठ +अगासी +जस्ता +थेरेपी +मैथुन +लोकल +सूर +यात्राओं +गेंदों +चढ़ +गाजीपुर +भागीदार +राहु +सजाया +उत्पीड़न +ओमान +बायीं +तुर्कमेनिस्तान +फेस +धड़ +वन्यजीव +चीज़ों +अनमोल +निभाते +जैसें +मुंशी +सुपरमैन +बहारी +विकिस्रोत +दुग्ध +लगीं +गुड्डी +माउस +आग़ा +गोरखा +कसौटी +अल्फ्रेड +पूज्य +वोक्सवैगन +ख़ +तना +ट्रैफिक +खंडित +मो +्षक +नायडू +शबाना +आतंकवादियों +जाली +लिविंग +पुनरावृत्ति +एक्सप्लोरर +फ़ोर्स +श्रोता +राजनयिक +तुल्य +डेज़ +फ्रेड +परोसा +ची +फोर्ब्स +कण्ठ +बर +कीन +प्रतिभागियों +सुरेन्द्र +फाइलों +निद्रा +बंगलोर +संभावनाओं +बॉस्टन +हार्ले +प्रोसेसिंग +नासिक +वाइड +एनर्जी +पकवान +दारा +कम्पनियों +थोडा +नवादा +सप्त +शाहरुख़ +तांबे +नग्न +अंजाम +तुग़लक़ +बचाया +बैनर्जी +बादलों +संप्रेषण +लैरी +९८ +डायमंड +शुभारंभ +अपार +देगा। +खिड़की +जश्न +मैनपुरी +विधाओं +६६ +भ्रामक +तंत्रों +सीरिज़ +लहरों +पुस्तकालयों +विनाशकारी +जैज़ +खतना +बस्तियां +उत्कर्ष +कोशिकाएँ +नेहरु +मेड +लिखा। +धनात्मक +चॉकलेट +मनोरमा +१९५२ +बार्सिलोना +लावा +फैजाबाद +वाटर्स +प्रात +बढ +विद्युत्‌ +मसलन +मसूरी +अचार +सटीकता +कीर्तिमान +ब्रिगेड +प्रकाशीय +कं +उत्साहित +नौकर +वारिस +नामदेव +हेमंत +ईंटों +इंटेलिजेंस +सपाट +गोबर +पर्सनल +कार्यप्रणाली +असीम +कॉलम +झाँसी +प्रबन्ध +करिश्मा +मिसिसिपी +ब्रेकिंग +निभा +खाती +दावों +वोल्ट +आप्रवासी +धड़कन +बिताया +प्रशस्त +बीटल +महलों +निलंबित +एबरडीन +लूथर +बारबरा +खण्डों +यूज़र +बर्बाद +उन्नयन +वेल्लोर +राजबब्बर +समन्वित +लोप +हल्दी +बुद्धिमान +किराए +८८ +अनुसन्धान +जेड +बादाम +पासपोर्ट +खुलता +माकपा +प्रमाणन +वृन्दावन +सड़कें +बम्बोर +पोषित +सिन्दूर +अमोनिया +श्रुति +उठाए +तकनीकें +पदवी +ऑर +गड़बड़ी +आमाशय +नरक +मुहैया +गुजरने +संग्रहीत +जेसन +सीक्रेट +असिमोव +कन्याकुमारी +र्व +झारखण्ड +उत्तराख +परिपक्वता +८१ +कौरव +ज्ञानकोश +रंगोली +गान्धी +ध्वनियों +कनाडाई +छिपे +म्हणोनि +प्रणालियाँ +विखंडन +गुम्बद +किक +बख़्तियारपुर +वश +नैस्टर +शा +बर्गर +फ़ल +हुवा +बिक +अटलांटा +रोधी +बचना +घा +लुटेरे +मेगाडेथ +बीजों +वियना +चिन्तन +अय्यर +सोम +चिन्हित +रेफरी +सहिष्णुता +छोड़ना +मसले +उद्यमी +जुलते +स्लोवाकिया +साख +गोकुल +दरबारी +बढ़ाई +देखा। +खूबसूरती +पैसेंजर +फ्लाइट +हवाओं +पीढी +नौगांव +आगंतुक +लिली +उत्तरकाशी +गुरुत्व +सिखाया +पियरे +शीर् +सिक्स +डब्ल्यूडब्ल्यूएफ +प्री +दशमलव +तेतिहा +क़ानूनी +धृतराष्ट्र +हाजीपुर +आर्यभट्ट +प्रायोजक +सन्दूक +सांसारिक +फलित +नामका +भट्टी +पांव +त् +सम्पादित +शोधन +विश्‍वविद्यालय +कंस +पम्प +चलाई +करतीं +ईपू +मिज़ोरम +हीन्दीवीकीपीडीयाके +दायें +अयोग्य +मृग +आनेवाले +लीबिया +लेसनर +तुमको +मेहमान +मेलबोर्न +स्‍थापना +थर्ड +इमेजिंग +सम्मेलनों +अमज़द +लगेगा +बेड़े +इब्राहिम +पक्का +पलट +मानदंडों +त्रिनिदाद +साम्राज्यवाद +परीक्षक +पड़ाव +पहाडी +जुड़ना +विलोपन +सिलसिले +खींचने +चलाए +जानकर +बेली +विचारकों +पितामह +नॉर्मन +डिपार्टमेंट +स्वादिष्ट +सुगंध +पेस +समता +गोंडा +लेस +फैलाने +सैनी +पिज़्ज़ा +रामधारी +तांत्रिक +साध्य +जन्मभूमि +संभालने +आकृतियों +अख्तर +हेल +तवी +पांडवों +मीलकर +उत्खनन +स्वैच्छिक +दिल्‍ली +श्रीलंकाई +दोहराया +मुखर +टोयोटा +रिपोर्टिंग +निषिद्ध +गंगोत्री +डिक +परमार +बार्न +फ़ैल +इण्डोनेशिया +अकादमिक +ड्राफ्ट +भूकम्प +दिखलाई +धर्मशास्त्र +किये। +क्राई +बकरी +पाया। +न्यूर्क +जौहर +कामयाबी +फौज +सुव्यवस्थित +डॉक्टरों +बढ़त +क्योटो +दर्जन +जुटाने +कलर +हिन +ग् +प्रेरण +एथलेटिक्स +कपाल +जस्टिन +पश्तो +कुंभ +थाइलैंड +बांस +ँव +कनेक्टिकट +जोरदार +बेरोजगारी +सुल्तानपुर +बिस्तर +खींचा +प्रौढ़ +एल्बमों +कड़ा +मानकीकृत +सामंत +वृहत +परबत्ता +दुल्हिनबाजार +सोल +चना +भोसले +सप्ताहांत +विशालकाय +धोने +भस्म +रहनेवाले +टेघरा +अमीन +फ़्रान्सीसी +शल्यक्रिया +ग्रांट +१९२१ +सांकेतिक +फार +मदिरा +पोर्शे +परिधान +यूरेनियम +जिन्होने +बलात्कार +परीक्षाओं +उत्तराखण +ट्रेक +जन्में +पि +पवित्रता +इंतजार +लाता +वादन +महत्‍वपूर्ण +ब् +अल्जीरिया +सीखना +नगण्य +खत्री +चतुर्भुज +बाक़ी +१९०० +टेन +करोड़ों +स्क्रीनिंग +टूटने +प्रजातियाँ +आन्तरिक +कहो +अपघटन +देशो +ब्रेट +पहुँचे। +परिस्थितियां +म् +पुनर्निर्देशित +नतीजा +साइबर +पैदावार +स्याही +नंदा +सैटेलाइट +न्यूट्रॉन +रोनाल्ड +देवेन +चमकदार +जिगर +योजनाएं +प्लेग +अध्यात्म +विदेशियों +सच्ची +चट्टोपाध्याय +दार्शनिकों +परिसंपत्ति +ओक +जाये। +इलाक़े +तुमसे +बिखरे +व्यवहारिक +तराखण्ड +मऊ +प्लूटो +दुखी +ताम्र +इल्म +फैलता +समतुल्य +किरणें +पेव्ड +हुमायूँ +सईद +भाभी +अंडमान +चूक +रणधीर +इब्न +बो +बॉस +उपराष्ट्रपति +वू +स्पीकर +च्वाइस +स्टुअर्ट +प्रदाताओं +कार्गो +डेन्जोंगपा +महज +सीतापुर +लगान +पेंटल +अनुसूची +हस्तियों +बहू +कुलीन +किनारा +कुलकर्णी +धनराशि +छुटकारा +बगीचे +शिरा +देखती +हीन +मद +बीट +वर्धित +संभाला +नीच +बेंज +जम +जप +गियर +एफएम +आरोपित +सोन +ठाकरे +स्टीवर्ट +पाण्डेय +आयकर +स्वार्थ +जन्मतिथि +विज्ञप्ति +न् +रीज़न +म्हणौनि +वत +रणनीतिक +शु +अत्याधिक +खालसा +प्रान्तों +कैलोरी +१२० +विनिर्देश +अमावस्या +गोलियों +जिन्दगी +अशुद्ध +स्मिता +वार्तालाप +दाखिल +काउबॉय +एक्टर्स +टेनेसी +पराबैंगनी +घूमती +खुलने +हिरण +संचारित +लैला +लाभप्रद +प्वाइंट +नर्तक +जासूसी +मानवों +शाहपुर +गुड़िया +अनुग्रह +९५ +विश्लेषक +जहांगीर +ही। +त्रिशूल +मनीश +स्पैरो +कोंकणी +सेक्टर +रिवर +यथासंभव +साम्यवाद +हडसन +सेव +चैंपियंस +बसों +किपलिंग +लड़ +विकिपिडिया +घनिष्ठ +दीवारें +टॉक +क्रमपरिवर्तन +म्यूजियम +प्लान +केसरी +फैमिली +लातिन +आर्द्रता +घाना +अस्मिता +बट +छड़ी +कात्यायन +पुनर्जन्म +ग्लूकोज़ +अज्ञेय +फिटनेस +प्रतिभाशाली +कलाकृतियों +हीलियम +दोहा +अंधेरे +तापीय +मल्टी +टीकू +आर्किटेक्चर +किन्हीं +सत्यापन +बलूचिस्तान +लारा +फिशर +रिहा +देवा +गॉड +सुनाया +वेश +सबौर +प्रशान्त +चिंताओं +तंजानिया +जाएँ। +संयोजी +साँचों +पूछ +श्राद्ध +मात +टैंगो +अमरनाथ +जानकार +कृषक +पेले +गुणसूत्र +पहियों +जिज्ञासा +टिप्पणियों +कहलाने +मोनोक्रोम +हीरालाल +बारीक +देंगे। +चित +छोड़ते +क़ुरान +यमन +आदर्शों +अपन +संघटन +विषयवस्तु +आमदनी +स्क्वैश +दर्शनों +सूरदास +मातृभूमि +फेंकने +१९५३ +दोस्ताना +लैण्ड +योजन +लॉर्ड्स +अभि +यूएफओ +विध्वंस +भूपति +नदाल +प्रतिभूतियों +ट्री +टॉमी +संप्रदायों +६२ +वैयक्तिक +भेजता +मल्टीमीडिया +आयामी +गुड़ +ट्रॉफी +आविष्कारक +हुईं। +लॉयड +चिह्नों +बिशप +साँप +हेवी +पर्यवेक्षण +ाद +चिन्ता +आलम +चौबीस +तलसानिया +ताड़ +दायित्वों +गलतियाँ +रिएक्टर +चंद्रगुप्त +सप्तम +नाइजीरिया +स्थ +गुदा +त्यों +मिटटी +कर्ज़ +बॉन +६७ +तात्कालिक +गार्डनर +अनूठा +ओड़िआ +रीटा +विश्लेषणात्मक +देवरिया +नेवर +्दी +चिकनी +डेटिंग +पोर्टेबल +उगाया +बालकों +स्पोर्ट +१९५१ +द्रोण +आवंटित +गांगुली +नार्वे +यन्त्र +देशपांडे +८२ +प्याज +एसएमएस +तूं +संहार +अलौली +शकीरा +छू +देवकी +गोल्डबर्ग +मशीनें +कर्ज +चढ़ने +हिमानी +बतलाया +बंगलुरु +पढाई +नेम +फ़ैसला +प्रीतम +हिरासत +मुबारक +खा०प० +डिप्लोमा +कॉनकॉर्ड +समझकर +संदर्म +एलर्जी +नितांत +उठने +मेरिल +गोपनीय +सुगम +क़ी +ाखण्ड +युग्म +बढ़ना +अबाउट +वहा +चला। +वतन +बाधाओं +हुबली +हीट +फुल +अनुपस्थित +येल +भावुक +पित्ताशय +टिन +लड़ा +रॉकी +नोल्स +वमन +मारना +ब्लाक +बहोत +कूपर +करो। +प्रमाणपत्र +यूट्यूब +सम्मलेन +रनवे +पूँजी +मंडप +पोटेशियम +उत्तरांचल +ठेठ +ओडिशा +पल्लव +इन्दौर +तर्ज़ +ः +अनूप +आओ +कुख्यात +बांसुरी +अनुपयुक्त +मगरमच्छ +स्पा +सेबी +चाहा +धमनियों +बारें +अश्व +हस्तिनापुर +ईसाइयों +आइपॉड +१०१ +इराकी +रयान +ाल +हिमनद +अमरावती +गिरी +पूछने +प्रेषित +घटाने +डिस्कवरी +पथरी +रायबरेली +नायनमार +बढती +मिलेगी +किशोरों +साड़ी +शिवजी +पुनर्वास +सहरसा +कैरोलिना +आरण्यक +असुर +लौंग +समाविष्ट +ज़ोन +फकीर +बियोवुल्फ़ +राइस +थेफ्ट +लू +ल० +अज़ाब +वेबदुनिया +ल्यूकेमिया +मार्गरेट +संन्यास +रनों +सुनहरे +सबने +विरल +पॉलिसी +रश +कैमरों +एंजेल्स +प्राणायाम +सेलिब्रिटी +कण्डारस्यूं +शाश्वत +जुलूस +विश +जेफ +मतानुसार +उत्पात +मामा +७३ +रहीं। +क्लिंटन +विकिया +आइवी +लिस्ट +आबू +गोमती +पुरुषोत्तम +उत्तराखण् +हेराल्ड +दांता +पद्मश्री +शर्तें +कटिहार +स्विंग +उत्तरार्द्ध +सिंगल्स +केदार +रघु +वासना +पहुँचकर +न्यूकैसल +मांगी +अमल +सल्फर +छोड +अंजना +कंप्यूटरों +ढ +विलिस +सीकर +जुड़ता +प्रसन्नता +प्लेटफॉर्म +गिरि +उछाल +करीना +जहर +मासके +सम्पदा +चौदहवीं +ढाईज्यूली +साओ +कोचीन +श्रावण +अर्पित +मासूम +टीन +स्पार्क +कट्टर +चढ़ा +ट्रिब्यून +होंडा +कीये +एंटोनियो +लैस +किससे +एकजुट +पतंग +१९२७ +टीकाकरण +मूक +असरगंज +सतहों +नाल +आयताकार +चढ़ाव +कार्यशील +दक्षिणपूर्व +माथे +मर्फी +गुजरता +सफ़र +स्लोवेनिया +रिले +कॉमन +जमाव +कुलभूषण +्स +क्रोम +उजाला +मूत्राशय +इस्राइल +नाड़ी +ंवत +परगना +लैंडिंग +रेलगाड़ी +कलाँ +उद्धार +ज़रिये +शॉर्ट +टिक +डिज़नी +फिल्माया +मरते +निष्कर्षों +उलट +भीमसेन +चक्रों +मात्राओं +प्रणाम +सिम्बियन +संस्थागत +बिताने +आंग्ल +बिजनौर +फायदे +खेड़ा +कार्यभार diff --git a/libs/harfbuzz/src/Makefile.am b/libs/harfbuzz/src/Makefile.am deleted file mode 100644 index 225444e32..000000000 --- a/libs/harfbuzz/src/Makefile.am +++ /dev/null @@ -1,522 +0,0 @@ -# Process this file with automake to produce Makefile.in - -NULL = -SUBDIRS = -DIST_SUBDIRS = -BUILT_SOURCES = -EXTRA_DIST = -CLEANFILES = -DISTCLEANFILES = -MAINTAINERCLEANFILES = -DISTCHECK_CONFIGURE_FLAGS = --enable-introspection -TESTS = -check_PROGRAMS = - -EXTRA_DIST += harfbuzz.cc harfbuzz-subset.cc -EXTRA_DIST += meson.build -EXTRA_DIST += fix_get_types.py - -# Convenience targets: -lib: $(BUILT_SOURCES) libharfbuzz.la -libs: $(BUILT_SOURCES) $(lib_LTLIBRARIES) -tiny: - $(MAKE) $(AM_MAKEFLAGS) CPPFLAGS="-Os -DHB_TINY $(CPPFLAGS)" libs -tinyz: - $(MAKE) $(AM_MAKEFLAGS) CPPFLAGS="-Oz -DHB_TINY $(CPPFLAGS)" libs - -lib_LTLIBRARIES = libharfbuzz.la - -include Makefile.sources - -HBCFLAGS = -HBLIBS = -HBNONPCLIBS = -HBDEPS = -HBSOURCES = $(HB_BASE_sources) -HBSOURCES += $(HB_BASE_RAGEL_GENERATED_sources) -HBHEADERS = $(HB_BASE_headers) - -if HAVE_PTHREAD -HBCFLAGS += $(PTHREAD_CFLAGS) -HBNONPCLIBS += $(PTHREAD_LIBS) -endif - -if HAVE_GLIB -HBCFLAGS += $(GLIB_CFLAGS) -HBLIBS += $(GLIB_LIBS) -HBDEPS += $(GLIB_DEPS) -HBSOURCES += $(HB_GLIB_sources) -HBHEADERS += $(HB_GLIB_headers) -endif - -if HAVE_FREETYPE -HBCFLAGS += $(FREETYPE_CFLAGS) -HBLIBS += $(FREETYPE_LIBS) -HBDEPS += $(FREETYPE_DEPS) -HBSOURCES += $(HB_FT_sources) -HBHEADERS += $(HB_FT_headers) -endif - -if HAVE_GRAPHITE2 -HBCFLAGS += $(GRAPHITE2_CFLAGS) -HBLIBS += $(GRAPHITE2_LIBS) -HBDEPS += $(GRAPHITE2_DEPS) -HBSOURCES += $(HB_GRAPHITE2_sources) -HBHEADERS += $(HB_GRAPHITE2_headers) -endif - -if HAVE_UNISCRIBE -HBCFLAGS += $(UNISCRIBE_CFLAGS) -HBNONPCLIBS += $(UNISCRIBE_LIBS) -HBSOURCES += $(HB_UNISCRIBE_sources) -HBHEADERS += $(HB_UNISCRIBE_headers) -endif - -if HAVE_DIRECTWRITE -HBCFLAGS += $(DIRECTWRITE_CXXFLAGS) -HBNONPCLIBS += $(DIRECTWRITE_LIBS) -HBSOURCES += $(HB_DIRECTWRITE_sources) -HBHEADERS += $(HB_DIRECTWRITE_headers) -endif - -if HAVE_GDI -HBCFLAGS += $(GDI_CXXFLAGS) -HBNONPCLIBS += $(GDI_LIBS) -HBSOURCES += $(HB_GDI_sources) -HBHEADERS += $(HB_GDI_headers) -endif - -if HAVE_CORETEXT -HBCFLAGS += $(CORETEXT_CFLAGS) -HBNONPCLIBS += $(CORETEXT_LIBS) -HBSOURCES += $(HB_CORETEXT_sources) -HBHEADERS += $(HB_CORETEXT_headers) -endif - - -BUILT_SOURCES += \ - hb-version.h - -$(srcdir)/hb-version.h: hb-version.h.in $(top_srcdir)/configure.ac - $(AM_V_GEN) $(SED) \ - -e 's/[@]HB_VERSION_MAJOR@/$(HB_VERSION_MAJOR)/' \ - -e 's/[@]HB_VERSION_MINOR@/$(HB_VERSION_MINOR)/' \ - -e 's/[@]HB_VERSION_MICRO@/$(HB_VERSION_MICRO)/' \ - -e 's/[@]HB_VERSION@/$(HB_VERSION)/' \ - "$<" > "$@" || ($(RM) "$@"; false) - -# Put the library together - -HBLIBS += $(HBNONPCLIBS) - -if OS_WIN32 -export_symbols = -export-symbols harfbuzz.def -harfbuzz_def_dependency = harfbuzz.def -export_symbols_subset = -export-symbols harfbuzz-subset.def -harfbuzz_subset_def_dependency = harfbuzz-subset.def -export_symbols_icu = -export-symbols harfbuzz-icu.def -harfbuzz_icu_def_dependency = harfbuzz-icu.def -export_symbols_gobject = -export-symbols harfbuzz-gobject.def -harfbuzz_gobject_def_dependency = harfbuzz-gobject.def -chosen_linker = $(CXXLINK) -else -if WITH_LIBSTDCXX -chosen_linker = $(CXXLINK) -else -if HAVE_GCC -# Use a C linker for GCC, not C++; Don't link to libstdc++ -chosen_linker = $(LINK) -else -chosen_linker = $(CXXLINK) -endif -endif -endif - -@CODE_COVERAGE_RULES@ - -base_link_flags = $(AM_LDFLAGS) -lm -version-info $(HB_LIBTOOL_VERSION_INFO) -no-undefined -libharfbuzz_la_LINK = $(chosen_linker) $(libharfbuzz_la_LDFLAGS) -libharfbuzz_la_SOURCES = $(HBSOURCES) $(HBHEADERS) -libharfbuzz_la_CPPFLAGS = $(HBCFLAGS) $(CODE_COVERAGE_CFLAGS) -libharfbuzz_la_LDFLAGS = $(base_link_flags) $(export_symbols) $(CODE_COVERAGE_LDFLAGS) -libharfbuzz_la_LIBADD = $(HBLIBS) -EXTRA_libharfbuzz_la_DEPENDENCIES = $(harfbuzz_def_dependency) -pkginclude_HEADERS = $(HBHEADERS) -nodist_pkginclude_HEADERS = -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = harfbuzz.pc -cmakedir = $(libdir)/cmake/harfbuzz -cmake_DATA = harfbuzz-config.cmake -EXTRA_DIST += hb-version.h.in harfbuzz.pc.in harfbuzz-config.cmake.in - -lib_LTLIBRARIES += libharfbuzz-subset.la -libharfbuzz_subset_la_LINK = $(chosen_linker) $(libharfbuzz_subset_la_LDFLAGS) -libharfbuzz_subset_la_SOURCES = $(HB_SUBSET_sources) -libharfbuzz_subset_la_CPPFLAGS = $(HBCFLAGS) $(CODE_COVERAGE_CFLAGS) -libharfbuzz_subset_la_LDFLAGS = $(base_link_flags) $(export_symbols_subset) $(CODE_COVERAGE_LDFLAGS) -libharfbuzz_subset_la_LIBADD = libharfbuzz.la -EXTRA_libharfbuzz_subset_la_DEPENDENCIES = $(harfbuzz_subset_def_dependency) -pkginclude_HEADERS += $(HB_SUBSET_headers) -pkgconfig_DATA += harfbuzz-subset.pc -EXTRA_DIST += harfbuzz-subset.pc.in - -harfbuzz-subset.cc: Makefile.sources - $(AM_V_GEN) \ - LANG=C; \ - for f in \ - $(HB_BASE_sources) \ - $(HB_SUBSET_sources) \ - ; do echo '#include "'$$f'"'; done | \ - sort -u | \ - grep '[.]cc"' > $(srcdir)/harfbuzz-subset.cc \ - || ($(RM) $(srcdir)/harfbuzz-subset.cc; false) -BUILT_SOURCES += harfbuzz-subset.cc - -if HAVE_ICU -if HAVE_ICU_BUILTIN -HBCFLAGS += $(ICU_CFLAGS) -HBLIBS += $(ICU_LIBS) -HBSOURCES += $(HB_ICU_sources) -HBHEADERS += $(HB_ICU_headers) -else -lib_LTLIBRARIES += libharfbuzz-icu.la -libharfbuzz_icu_la_SOURCES = $(HB_ICU_sources) -libharfbuzz_icu_la_CPPFLAGS = $(HBCFLAGS) $(ICU_CFLAGS) $(CODE_COVERAGE_CFLAGS) -libharfbuzz_icu_la_LDFLAGS = $(base_link_flags) $(export_symbols_icu) $(CODE_COVERAGE_LDFLAGS) -libharfbuzz_icu_la_LIBADD = $(ICU_LIBS) libharfbuzz.la -EXTRA_libharfbuzz_icu_la_DEPENDENCIES = $(harfbuzz_icu_def_dependency) -pkginclude_HEADERS += $(HB_ICU_headers) -pkgconfig_DATA += harfbuzz-icu.pc -endif -endif -EXTRA_DIST += harfbuzz-icu.pc.in - -if HAVE_GOBJECT -lib_LTLIBRARIES += libharfbuzz-gobject.la -libharfbuzz_gobject_la_LINK = $(chosen_linker) $(libharfbuzz_gobject_la_LDFLAGS) -libharfbuzz_gobject_la_SOURCES = $(HB_GOBJECT_DIST_sources) -nodist_libharfbuzz_gobject_la_SOURCES = $(HB_GOBJECT_NODIST_sources) -libharfbuzz_gobject_la_CPPFLAGS = $(HBCFLAGS) $(GOBJECT_CFLAGS) $(CODE_COVERAGE_CFLAGS) -libharfbuzz_gobject_la_LDFLAGS = $(base_link_flags) $(CODE_COVERAGE_LDFLAGS) -libharfbuzz_gobject_la_LIBADD = $(GOBJECT_LIBS) libharfbuzz.la -EXTRA_libharfbuzz_gobject_la_DEPENDENCIES = $(harfbuzz_gobject_def_dependency) -pkginclude_HEADERS += $(HB_GOBJECT_DIST_headers) -nodist_pkginclude_HEADERS += $(HB_GOBJECT_NODIST_headers) -pkgconfig_DATA += harfbuzz-gobject.pc - -BUILT_SOURCES += \ - $(HB_GOBJECT_ENUM_sources) \ - $(HB_GOBJECT_ENUM_headers) \ - $(NULL) -DISTCLEANFILES += \ - $(HB_GOBJECT_ENUM_sources) \ - $(HB_GOBJECT_ENUM_headers) \ - $(NULL) -hb-gobject-enums.%: hb-gobject-enums.%.tmpl $(HBHEADERS) - $(AM_V_GEN) PYTHONIOENCODING=UTF-8 $(GLIB_MKENUMS) \ - --identifier-prefix hb_ --symbol-prefix hb_gobject \ - --template $^ | \ - sed 's/_t_get_type/_get_type/g; s/_T (/ (/g' > "$@" \ - || ($(RM) "$@"; false) -endif -EXTRA_DIST += \ - harfbuzz-gobject.pc.in \ - hb-gobject-enums.cc.tmpl \ - hb-gobject-enums.h.tmpl \ - $(NULL) - - -%.pc: %.pc.in $(top_builddir)/config.status - $(AM_V_GEN) \ - $(SED) -e 's@%prefix%@$(prefix)@g' \ - -e 's@%exec_prefix%@$(exec_prefix)@g' \ - -e 's@%libdir%@$(libdir)@g' \ - -e 's@%includedir%@$(includedir)@g' \ - -e 's@%libs_private%@$(HBNONPCLIBS)@g' \ - -e 's@%requires_private%@$(HBDEPS)@g' \ - -e 's@%VERSION%@$(VERSION)@g' \ - "$<" > "$@" \ - || ($(RM) "$@"; false) - -CLEANFILES += $(pkgconfig_DATA) - - -DEF_FILES = harfbuzz.def harfbuzz-subset.def harfbuzz-icu.def harfbuzz-deprecated-symbols.txt -if HAVE_GOBJECT -DEF_FILES += harfbuzz-gobject.def -endif -check: $(DEF_FILES) # For check-symbols.sh -CLEANFILES += $(DEF_FILES) -harfbuzz.def: $(top_builddir)/config.status -harfbuzz.def: $(HBHEADERS) - $(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^ -harfbuzz-subset.def: $(HB_SUBSET_headers) - $(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^ -harfbuzz-icu.def: $(HB_ICU_headers) - $(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^ -harfbuzz-gobject.def: $(HB_GOBJECT_headers) - $(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^ -harfbuzz-deprecated-symbols.txt: $(srcdir)/hb-deprecated.h - $(AM_V_GEN) PLAIN_LIST=1 $(srcdir)/gen-def.py "$@" $^ - - -GENERATORS = \ - gen-arabic-joining-list.py \ - gen-arabic-table.py \ - gen-def.py \ - gen-emoji-table.py \ - gen-harfbuzzcc.py \ - gen-hb-version.py \ - gen-indic-table.py \ - gen-os2-unicode-ranges.py \ - gen-ragel-artifacts.py \ - gen-tag-table.py \ - gen-ucd-table.py \ - gen-use-table.py \ - gen-vowel-constraints.py \ - $(NULL) -EXTRA_DIST += $(GENERATORS) - -built-sources: $(BUILT_SOURCES) - -.PHONY: built-sources - -RAGEL_GENERATED = \ - $(patsubst %,$(srcdir)/%,$(HB_BASE_RAGEL_GENERATED_sources)) \ - $(NULL) -BUILT_SOURCES += $(RAGEL_GENERATED) -EXTRA_DIST += \ - $(HB_BASE_RAGEL_sources) \ - $(NULL) -# We decided to add ragel-generated files to git... -#MAINTAINERCLEANFILES += $(RAGEL_GENERATED) -$(srcdir)/%.hh: $(srcdir)/%.rl - $(AM_V_GEN)(cd $(srcdir) && $(RAGEL) -e -F1 -o "$*.hh" "$*.rl") \ - || ($(RM) "$@"; false) - -harfbuzz.cc: Makefile.sources - $(AM_V_GEN) \ - LANG=C; \ - for f in \ - $(HB_BASE_sources) \ - $(HB_GLIB_sources) \ - $(HB_FT_sources) \ - $(HB_GRAPHITE2_sources) \ - $(HB_UNISCRIBE_sources) \ - $(HB_GDI_sources) \ - $(HB_DIRECTWRITE_sources) \ - $(HB_CORETEXT_sources) \ - ; do echo '#include "'$$f'"'; done | \ - sort -u | \ - grep '[.]cc"' > $(srcdir)/harfbuzz.cc \ - || ($(RM) $(srcdir)/harfbuzz.cc; false) -BUILT_SOURCES += harfbuzz.cc - -noinst_PROGRAMS = \ - main \ - test \ - test-buffer-serialize \ - test-ot-meta \ - test-ot-name \ - test-ot-glyphname \ - test-gpos-size-params \ - test-gsub-would-substitute \ - test-use-table \ - $(NULL) -bin_PROGRAMS = - -main_SOURCES = main.cc -main_CPPFLAGS = $(HBCFLAGS) -main_LDADD = libharfbuzz.la $(HBLIBS) - -test_SOURCES = test.cc -test_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS) -test_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS) - -test_buffer_serialize_SOURCES = test-buffer-serialize.cc -test_buffer_serialize_CPPFLAGS = $(HBCFLAGS) -test_buffer_serialize_LDADD = libharfbuzz.la $(HBLIBS) - -test_ot_meta_SOURCES = test-ot-meta.cc -test_ot_meta_CPPFLAGS = $(HBCFLAGS) -test_ot_meta_LDADD = libharfbuzz.la $(HBLIBS) - -test_ot_name_SOURCES = test-ot-name.cc -test_ot_name_CPPFLAGS = $(HBCFLAGS) -test_ot_name_LDADD = libharfbuzz.la $(HBLIBS) - -test_ot_glyphname_SOURCES = test-ot-glyphname.cc -test_ot_glyphname_CPPFLAGS = $(HBCFLAGS) -test_ot_glyphname_LDADD = libharfbuzz.la $(HBLIBS) - -test_use_table_SOURCES = test-use-table.cc -test_use_table_CPPFLAGS = $(HBCFLAGS) -test_use_table_LDADD = libharfbuzz.la $(HBLIBS) - -test_gpos_size_params_SOURCES = test-gpos-size-params.cc -test_gpos_size_params_CPPFLAGS = $(HBCFLAGS) -test_gpos_size_params_LDADD = libharfbuzz.la $(HBLIBS) - -test_gsub_would_substitute_SOURCES = test-gsub-would-substitute.cc -test_gsub_would_substitute_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS) -test_gsub_would_substitute_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS) - -COMPILED_TESTS = \ - test-algs \ - test-array \ - test-bimap \ - test-iter \ - test-machinery \ - test-map \ - test-number \ - test-ot-tag \ - test-priority-queue \ - test-set \ - test-serialize \ - test-unicode-ranges \ - test-vector \ - test-repacker \ - test-classdef-graph \ - $(NULL) -COMPILED_TESTS_CPPFLAGS = $(HBCFLAGS) -DMAIN -UNDEBUG -COMPILED_TESTS_LDADD = libharfbuzz.la $(HBLIBS) -check_PROGRAMS += $(COMPILED_TESTS) -TESTS += $(COMPILED_TESTS) - -test_algs_SOURCES = test-algs.cc hb-static.cc -test_algs_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS) -test_algs_LDADD = $(COMPILED_TESTS_LDADD) - -test_array_SOURCES = test-array.cc -test_array_CPPFLAGS = $(HBCFLAGS) -test_array_LDADD = libharfbuzz.la $(HBLIBS) - -test_bimap_SOURCES = test-bimap.cc hb-static.cc -test_bimap_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS) -test_bimap_LDADD = $(COMPILED_TESTS_LDADD) - -test_iter_SOURCES = test-iter.cc hb-static.cc -test_iter_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS) -test_iter_LDADD = $(COMPILED_TESTS_LDADD) - -test_machinery_SOURCES = test-machinery.cc hb-static.cc -test_machinery_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS) -test_machinery_LDADD = $(COMPILED_TESTS_LDADD) - -test_map_SOURCES = test-map.cc hb-static.cc -test_map_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS) -test_map_LDADD = $(COMPILED_TESTS_LDADD) - -test_number_SOURCES = test-number.cc hb-number.cc -test_number_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS) -test_number_LDADD = $(COMPILED_TESTS_LDADD) - -test_ot_tag_SOURCES = hb-ot-tag.cc -test_ot_tag_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS) -test_ot_tag_LDADD = $(COMPILED_TESTS_LDADD) - -test_priority_queue_SOURCES = test-priority-queue.cc hb-static.cc -test_priority_queue_CPPFLAGS = $(HBCFLAGS) -test_priority_queue_LDADD = libharfbuzz.la $(HBLIBS) - -test_repacker_SOURCES = test-repacker.cc hb-static.cc graph/gsubgpos-context.cc -test_repacker_CPPFLAGS = $(HBCFLAGS) -test_repacker_LDADD = libharfbuzz.la libharfbuzz-subset.la $(HBLIBS) - -test_classdef_graph_SOURCES = graph/test-classdef-graph.cc hb-static.cc graph/gsubgpos-context.cc -test_classdef_graph_CPPFLAGS = $(HBCFLAGS) -test_classdef_graph_LDADD = libharfbuzz.la libharfbuzz-subset.la $(HBLIBS) - -test_set_SOURCES = test-set.cc hb-static.cc -test_set_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS) -test_set_LDADD = $(COMPILED_TESTS_LDADD) - -test_serialize_SOURCES = test-serialize.cc hb-static.cc -test_serialize_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS) -test_serialize_LDADD = $(COMPILED_TESTS_LDADD) - -test_unicode_ranges_SOURCES = test-unicode-ranges.cc -test_unicode_ranges_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS) -test_unicode_ranges_LDADD = $(COMPILED_TESTS_LDADD) - -test_vector_SOURCES = test-vector.cc hb-static.cc -test_vector_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS) -test_vector_LDADD = $(COMPILED_TESTS_LDADD) - -dist_check_SCRIPTS = \ - check-c-linkage-decls.py \ - check-externs.py \ - check-header-guards.py \ - check-includes.py \ - check-static-inits.py \ - check-symbols.py \ - $(NULL) -TESTS += $(dist_check_SCRIPTS) - -if !WITH_LIBSTDCXX -dist_check_SCRIPTS += \ - check-libstdc++.py \ - $(NULL) -endif - -TESTS_ENVIRONMENT = \ - srcdir="$(srcdir)" \ - base_srcdir="$(srcdir)" \ - builddir="$(builddir)" \ - MAKE="$(MAKE) $(AM_MAKEFLAGS)" \ - HBSOURCES="$(HBSOURCES)" \ - HBHEADERS="$(HBHEADERS)" \ - LDD="$(LDD)" \ - NM="$(NM)" \ - OBJDUMP="$(OBJDUMP)" \ - OTOOL="$(OTOOL)" \ - $(NULL) - -if HAVE_INTROSPECTION - --include $(INTROSPECTION_MAKEFILE) -INTROSPECTION_GIRS = HarfBuzz-0.0.gir # What does the 0 mean anyway?! -INTROSPECTION_SCANNER_ARGS = \ - -I$(srcdir) \ - --warn-all --verbose \ - --namespace=HarfBuzz \ - --nsversion=0.0 \ - --symbol-prefix=hb \ - --symbol-prefix=hb_gobject \ - --identifier-prefix=hb_ \ - --pkg-export=harfbuzz-gobject \ - --c-include=hb-gobject.h -INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir) -INTROSPECTION_SCANNER_ENV = CC="$(CC)" - -HarfBuzz-0.0.gir: libharfbuzz.la libharfbuzz-gobject.la -HarfBuzz_0_0_gir_INCLUDES = GObject-2.0 freetype2-2.0 -HarfBuzz_0_0_gir_CFLAGS = \ - $(INCLUDES) \ - $(HBCFLAGS) \ - -DHB_NO_SINGLE_HEADER_ERROR \ - -DHAVE_GOBJECT \ - -DHB_EXTERN= \ - $(NULL) -HarfBuzz_0_0_gir_LIBS = \ - libharfbuzz.la \ - libharfbuzz-gobject.la \ - $(NULL) -HarfBuzz_0_0_gir_FILES = \ - $(HBHEADERS) \ - $(HBSOURCES) \ - $(HB_GOBJECT_sources) \ - $(HB_GOBJECT_headers) \ - $(NULL) - -girdir = $(datadir)/gir-1.0 -gir_DATA = $(INTROSPECTION_GIRS) - -typelibdir = $(libdir)/girepository-1.0 -typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib) - -CLEANFILES += $(gir_DATA) $(typelib_DATA) - -endif - --include $(top_srcdir)/git.mk diff --git a/libs/harfbuzz/src/Makefile.sources b/libs/harfbuzz/src/Makefile.sources deleted file mode 100644 index 6c891eac5..000000000 --- a/libs/harfbuzz/src/Makefile.sources +++ /dev/null @@ -1,375 +0,0 @@ -# Base and default-included sources and headers - -HB_BASE_sources = \ - hb-aat-layout-ankr-table.hh \ - hb-aat-layout-bsln-table.hh \ - hb-aat-layout-common.hh \ - hb-aat-layout-feat-table.hh \ - hb-aat-layout-just-table.hh \ - hb-aat-layout-kerx-table.hh \ - hb-aat-layout-morx-table.hh \ - hb-aat-layout-opbd-table.hh \ - hb-aat-layout-trak-table.hh \ - hb-aat-layout.cc \ - hb-aat-layout.hh \ - hb-aat-ltag-table.hh \ - hb-aat-map.cc \ - hb-aat-map.hh \ - hb-algs.hh \ - hb-array.hh \ - hb-atomic.hh \ - hb-bimap.hh \ - hb-bit-page.hh \ - hb-bit-set.hh \ - hb-bit-set-invertible.hh \ - hb-blob.cc \ - hb-blob.hh \ - hb-buffer-serialize.cc \ - hb-buffer-verify.cc \ - hb-buffer.cc \ - hb-buffer.hh \ - hb-cache.hh \ - hb-cff-interp-common.hh \ - hb-cff-interp-cs-common.hh \ - hb-cff-interp-dict-common.hh \ - hb-cff1-interp-cs.hh \ - hb-cff2-interp-cs.hh \ - hb-common.cc \ - hb-config.hh \ - hb-debug.hh \ - hb-dispatch.hh \ - hb-draw.cc \ - hb-draw.hh \ - hb-face.cc \ - hb-face.hh \ - hb-fallback-shape.cc \ - hb-font.cc \ - hb-font.hh \ - hb-iter.hh \ - hb-kern.hh \ - hb-machinery.hh \ - hb-map.cc \ - hb-map.hh \ - hb-meta.hh \ - hb-ms-feature-ranges.hh \ - hb-mutex.hh \ - hb-null.hh \ - hb-number.cc \ - hb-number.hh \ - hb-object.hh \ - hb-open-file.hh \ - hb-open-type.hh \ - hb-ot-cff-common.hh \ - hb-ot-cff1-std-str.hh \ - hb-ot-cff1-table.cc \ - hb-ot-cff1-table.hh \ - hb-ot-cff2-table.cc \ - hb-ot-cff2-table.hh \ - hb-ot-cmap-table.hh \ - hb-ot-color-cbdt-table.hh \ - hb-ot-color-colr-table.hh \ - hb-ot-color-cpal-table.hh \ - hb-ot-color-sbix-table.hh \ - hb-ot-color-svg-table.hh \ - hb-ot-color.cc \ - hb-ot-face-table-list.hh \ - hb-ot-face.cc \ - hb-ot-face.hh \ - hb-ot-font.cc \ - hb-ot-gasp-table.hh \ - hb-ot-glyf-table.hh \ - hb-ot-hdmx-table.hh \ - hb-ot-head-table.hh \ - hb-ot-hhea-table.hh \ - hb-ot-hmtx-table.hh \ - hb-ot-kern-table.hh \ - hb-ot-layout-base-table.hh \ - hb-ot-layout-common.hh \ - hb-ot-layout-gdef-table.hh \ - hb-ot-layout-gpos-table.hh \ - hb-ot-layout-gsub-table.hh \ - OT/glyf/glyf.hh \ - OT/glyf/glyf-helpers.hh \ - OT/glyf/loca.hh \ - OT/glyf/path-builder.hh \ - OT/glyf/Glyph.hh \ - OT/glyf/GlyphHeader.hh \ - OT/glyf/SimpleGlyph.hh \ - OT/glyf/CompositeGlyph.hh \ - OT/glyf/SubsetGlyph.hh \ - OT/Layout/types.hh \ - OT/Layout/Common/Coverage.hh \ - OT/Layout/Common/CoverageFormat1.hh \ - OT/Layout/Common/CoverageFormat2.hh \ - OT/Layout/Common/RangeRecord.hh \ - OT/Layout/GPOS/AnchorFormat1.hh \ - OT/Layout/GPOS/AnchorFormat2.hh \ - OT/Layout/GPOS/AnchorFormat3.hh \ - OT/Layout/GPOS/Anchor.hh \ - OT/Layout/GPOS/AnchorMatrix.hh \ - OT/Layout/GPOS/ChainContextPos.hh \ - OT/Layout/GPOS/Common.hh \ - OT/Layout/GPOS/ContextPos.hh \ - OT/Layout/GPOS/CursivePosFormat1.hh \ - OT/Layout/GPOS/CursivePos.hh \ - OT/Layout/GPOS/ExtensionPos.hh \ - OT/Layout/GPOS/GPOS.hh \ - OT/Layout/GPOS/LigatureArray.hh \ - OT/Layout/GPOS/MarkArray.hh \ - OT/Layout/GPOS/MarkBasePosFormat1.hh \ - OT/Layout/GPOS/MarkBasePos.hh \ - OT/Layout/GPOS/MarkLigPosFormat1.hh \ - OT/Layout/GPOS/MarkLigPos.hh \ - OT/Layout/GPOS/MarkMarkPosFormat1.hh \ - OT/Layout/GPOS/MarkMarkPos.hh \ - OT/Layout/GPOS/MarkRecord.hh \ - OT/Layout/GPOS/PairPosFormat1.hh \ - OT/Layout/GPOS/PairPosFormat2.hh \ - OT/Layout/GPOS/PairPos.hh \ - OT/Layout/GPOS/PairSet.hh \ - OT/Layout/GPOS/PairValueRecord.hh \ - OT/Layout/GPOS/PosLookup.hh \ - OT/Layout/GPOS/PosLookupSubTable.hh \ - OT/Layout/GPOS/SinglePosFormat1.hh \ - OT/Layout/GPOS/SinglePosFormat2.hh \ - OT/Layout/GPOS/SinglePos.hh \ - OT/Layout/GPOS/ValueFormat.hh \ - OT/Layout/GSUB/AlternateSet.hh \ - OT/Layout/GSUB/AlternateSubstFormat1.hh \ - OT/Layout/GSUB/AlternateSubst.hh \ - OT/Layout/GSUB/ChainContextSubst.hh \ - OT/Layout/GSUB/Common.hh \ - OT/Layout/GSUB/ContextSubst.hh \ - OT/Layout/GSUB/ExtensionSubst.hh \ - OT/Layout/GSUB/GSUB.hh \ - OT/Layout/GSUB/Ligature.hh \ - OT/Layout/GSUB/LigatureSet.hh \ - OT/Layout/GSUB/LigatureSubstFormat1.hh \ - OT/Layout/GSUB/LigatureSubst.hh \ - OT/Layout/GSUB/MultipleSubstFormat1.hh \ - OT/Layout/GSUB/MultipleSubst.hh \ - OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh \ - OT/Layout/GSUB/ReverseChainSingleSubst.hh \ - OT/Layout/GSUB/Sequence.hh \ - OT/Layout/GSUB/SingleSubstFormat1.hh \ - OT/Layout/GSUB/SingleSubstFormat2.hh \ - OT/Layout/GSUB/SingleSubst.hh \ - OT/Layout/GSUB/SubstLookup.hh \ - OT/Layout/GSUB/SubstLookupSubTable.hh \ - hb-ot-layout-gsubgpos.hh \ - hb-ot-layout-jstf-table.hh \ - hb-ot-layout.cc \ - hb-ot-layout.hh \ - hb-ot-map.cc \ - hb-ot-map.hh \ - hb-ot-math-table.hh \ - hb-ot-math.cc \ - hb-ot-maxp-table.hh \ - hb-ot-meta-table.hh \ - hb-ot-meta.cc \ - hb-ot-metrics.cc \ - hb-ot-metrics.hh \ - hb-ot-name-language-static.hh \ - hb-ot-name-language.hh \ - hb-ot-name-table.hh \ - hb-ot-name.cc \ - hb-ot-os2-table.hh \ - hb-ot-os2-unicode-ranges.hh \ - hb-ot-post-macroman.hh \ - hb-ot-post-table.hh \ - hb-ot-shaper-arabic-fallback.hh \ - hb-ot-shaper-arabic-joining-list.hh \ - hb-ot-shaper-arabic-pua.hh \ - hb-ot-shaper-arabic-table.hh \ - hb-ot-shaper-arabic-win1256.hh \ - hb-ot-shaper-arabic.cc \ - hb-ot-shaper-arabic.hh \ - hb-ot-shaper-default.cc \ - hb-ot-shaper-hangul.cc \ - hb-ot-shaper-hebrew.cc \ - hb-ot-shaper-indic-table.cc \ - hb-ot-shaper-indic.cc \ - hb-ot-shaper-indic.hh \ - hb-ot-shaper-khmer.cc \ - hb-ot-shaper-myanmar.cc \ - hb-ot-shaper-syllabic.cc \ - hb-ot-shaper-syllabic.hh \ - hb-ot-shaper-thai.cc \ - hb-ot-shaper-use-table.hh \ - hb-ot-shaper-use.cc \ - hb-ot-shaper-vowel-constraints.cc \ - hb-ot-shaper-vowel-constraints.hh \ - hb-ot-shaper.hh \ - hb-ot-shape-fallback.cc \ - hb-ot-shape-fallback.hh \ - hb-ot-shape-normalize.cc \ - hb-ot-shape-normalize.hh \ - hb-ot-shape.cc \ - hb-ot-shape.hh \ - hb-ot-stat-table.hh \ - hb-ot-tag-table.hh \ - hb-ot-tag.cc \ - hb-ot-var-avar-table.hh \ - hb-ot-var-common.hh \ - hb-ot-var-fvar-table.hh \ - hb-ot-var-gvar-table.hh \ - hb-ot-var-hvar-table.hh \ - hb-ot-var-mvar-table.hh \ - hb-ot-var.cc \ - hb-ot-vorg-table.hh \ - hb-pool.hh \ - hb-sanitize.hh \ - hb-serialize.hh \ - hb-set-digest.hh \ - hb-set.cc \ - hb-set.hh \ - hb-shape-plan.cc \ - hb-shape-plan.hh \ - hb-shape.cc \ - hb-shaper-impl.hh \ - hb-shaper-list.hh \ - hb-shaper.cc \ - hb-shaper.hh \ - hb-static.cc \ - hb-string-array.hh \ - hb-style.cc \ - hb-ucd-table.hh \ - hb-ucd.cc \ - hb-unicode-emoji-table.hh \ - hb-unicode.cc \ - hb-unicode.hh \ - hb-utf.hh \ - hb-vector.hh \ - hb-priority-queue.hh \ - hb.hh \ - $(NULL) - -HB_BASE_RAGEL_GENERATED_sources = \ - hb-buffer-deserialize-json.hh \ - hb-buffer-deserialize-text.hh \ - hb-number-parser.hh \ - hb-ot-shaper-indic-machine.hh \ - hb-ot-shaper-khmer-machine.hh \ - hb-ot-shaper-myanmar-machine.hh \ - hb-ot-shaper-use-machine.hh \ - $(NULL) -HB_BASE_RAGEL_sources = \ - hb-buffer-deserialize-json.rl \ - hb-buffer-deserialize-text.rl \ - hb-number-parser.rl \ - hb-ot-shaper-indic-machine.rl \ - hb-ot-shaper-khmer-machine.rl \ - hb-ot-shaper-myanmar-machine.rl \ - hb-ot-shaper-use-machine.rl \ - $(NULL) - -HB_BASE_headers = \ - hb-aat-layout.h \ - hb-aat.h \ - hb-blob.h \ - hb-buffer.h \ - hb-common.h \ - hb-cplusplus.hh \ - hb-deprecated.h \ - hb-draw.h \ - hb-face.h \ - hb-font.h \ - hb-map.h \ - hb-ot-color.h \ - hb-ot-deprecated.h \ - hb-ot-font.h \ - hb-ot-layout.h \ - hb-ot-math.h \ - hb-ot-meta.h \ - hb-ot-metrics.h \ - hb-ot-name.h \ - hb-ot-shape.h \ - hb-ot-var.h \ - hb-ot.h \ - hb-set.h \ - hb-shape-plan.h \ - hb-shape.h \ - hb-style.h \ - hb-unicode.h \ - hb-version.h \ - hb.h \ - $(NULL) - -# Optional Sources and Headers with external deps - -HB_FT_sources = hb-ft.cc -HB_FT_headers = hb-ft.h - -HB_GLIB_sources = hb-glib.cc -HB_GLIB_headers = hb-glib.h - -HB_GRAPHITE2_sources = hb-graphite2.cc -HB_GRAPHITE2_headers = hb-graphite2.h - -# System-dependent sources and headers - -HB_CORETEXT_sources = hb-coretext.cc -HB_CORETEXT_headers = hb-coretext.h - -HB_DIRECTWRITE_sources = hb-directwrite.cc -HB_DIRECTWRITE_headers = hb-directwrite.h - -HB_GDI_sources = hb-gdi.cc -HB_GDI_headers = hb-gdi.h - -HB_UNISCRIBE_sources = hb-uniscribe.cc -HB_UNISCRIBE_headers = hb-uniscribe.h - -# Sources for libharfbuzz-gobject and libharfbuzz-icu -HB_ICU_sources = hb-icu.cc -HB_ICU_headers = hb-icu.h - -# Sources for libharfbuzz-subset -HB_SUBSET_sources = \ - hb-number.cc \ - hb-number.hh \ - hb-ot-cff1-table.cc \ - hb-ot-cff2-table.cc \ - hb-ot-color-colrv1-closure.hh \ - hb-ot-post-table-v2subset.hh \ - hb-static.cc \ - hb-subset-cff-common.cc \ - hb-subset-cff-common.hh \ - hb-subset-cff1.cc \ - hb-subset-cff1.hh \ - hb-subset-cff2.cc \ - hb-subset-cff2.hh \ - hb-subset-input.cc \ - hb-subset-input.hh \ - hb-subset-accelerator.hh \ - hb-subset-plan.cc \ - hb-subset-plan.hh \ - hb-subset-repacker.cc \ - hb-subset.cc \ - hb-subset.hh \ - hb-repacker.hh \ - graph/graph.hh \ - graph/gsubgpos-graph.hh \ - graph/gsubgpos-context.hh \ - graph/gsubgpos-context.cc \ - graph/coverage-graph.hh \ - graph/classdef-graph.hh \ - graph/pairpos-graph.hh \ - graph/markbasepos-graph.hh \ - graph/split-helpers.hh \ - graph/serialize.hh \ - $(NULL) - -HB_SUBSET_headers = \ - hb-subset.h \ - hb-subset-repacker.h \ - $(NULL) - -HB_GOBJECT_DIST_sources = hb-gobject-structs.cc -HB_GOBJECT_DIST_headers = hb-gobject.h hb-gobject-structs.h -HB_GOBJECT_ENUM_sources = hb-gobject-enums.cc -HB_GOBJECT_ENUM_headers = hb-gobject-enums.h -HB_GOBJECT_NODIST_sources = $(HB_GOBJECT_ENUM_sources) -HB_GOBJECT_NODIST_headers = $(HB_GOBJECT_ENUM_headers) -HB_GOBJECT_sources = $(HB_GOBJECT_DIST_sources) $(HB_GOBJECT_NODIST_sources) -HB_GOBJECT_headers = $(HB_GOBJECT_DIST_headers) $(HB_GOBJECT_NODIST_headers) diff --git a/libs/harfbuzz/src/hb-ot-color-cbdt-table.hh b/libs/harfbuzz/src/OT/Color/CBDT/CBDT.hh similarity index 92% rename from libs/harfbuzz/src/hb-ot-color-cbdt-table.hh rename to libs/harfbuzz/src/OT/Color/CBDT/CBDT.hh index 23fa56c4f..bcf1848f4 100644 --- a/libs/harfbuzz/src/hb-ot-color-cbdt-table.hh +++ b/libs/harfbuzz/src/OT/Color/CBDT/CBDT.hh @@ -24,10 +24,11 @@ * Google Author(s): Seigo Nonaka, Calder Kitagawa */ -#ifndef HB_OT_COLOR_CBDT_TABLE_HH -#define HB_OT_COLOR_CBDT_TABLE_HH +#ifndef OT_COLOR_CBDT_CBDT_HH +#define OT_COLOR_CBDT_CBDT_HH -#include "hb-open-type.hh" +#include "../../../hb-open-type.hh" +#include "../../../hb-paint.hh" /* * CBLC -- Color Bitmap Location @@ -67,7 +68,7 @@ _copy_data_to_cbdt (hb_vector_t *cbdt_prime, { unsigned int new_len = cbdt_prime->length + length; if (unlikely (!cbdt_prime->alloc (new_len))) return false; - memcpy (cbdt_prime->arrayZ + cbdt_prime->length, data, length); + hb_memcpy (cbdt_prime->arrayZ + cbdt_prime->length, data, length); cbdt_prime->length = new_len; return true; } @@ -80,12 +81,15 @@ struct SmallGlyphMetrics return_trace (c->check_struct (this)); } - void get_extents (hb_font_t *font, hb_glyph_extents_t *extents) const + void get_extents (hb_font_t *font, hb_glyph_extents_t *extents, bool scale) const { - extents->x_bearing = font->em_scale_x (bearingX); - extents->y_bearing = font->em_scale_y (bearingY); - extents->width = font->em_scale_x (width); - extents->height = font->em_scale_y (-static_cast(height)); + extents->x_bearing = bearingX; + extents->y_bearing = bearingY; + extents->width = width; + extents->height = -static_cast (height); + + if (scale) + font->scale_glyph_extents (extents); } HBUINT8 height; @@ -200,6 +204,7 @@ struct IndexSubtable { TRACE_SANITIZE (this); if (!u.header.sanitize (c)) return_trace (false); + hb_barrier (); switch (u.header.indexFormat) { case 1: return_trace (u.format1.sanitize (c, glyph_count)); @@ -307,7 +312,7 @@ struct IndexSubtable } } - bool get_extents (hb_glyph_extents_t *extents HB_UNUSED) const + bool get_extents (hb_glyph_extents_t *extents HB_UNUSED, bool scale HB_UNUSED) const { switch (u.header.indexFormat) { @@ -374,6 +379,7 @@ struct IndexSubtableRecord { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && + hb_barrier () && firstGlyphIndex <= lastGlyphIndex && offsetToSubtable.sanitize (c, base, lastGlyphIndex - firstGlyphIndex + 1)); } @@ -393,7 +399,6 @@ struct IndexSubtableRecord TRACE_SERIALIZE (this); auto *subtable = c->serializer->start_embed (); - if (unlikely (!subtable)) return_trace (false); if (unlikely (!c->serializer->extend_min (subtable))) return_trace (false); auto *old_subtable = get_subtable (base); @@ -468,13 +473,13 @@ struct IndexSubtableRecord if (unlikely (!c->serializer->check_success (records->resize (records->length + 1)))) return_trace (false); - (*records)[records->length - 1].firstGlyphIndex = 1; - (*records)[records->length - 1].lastGlyphIndex = 0; + records->tail ().firstGlyphIndex = 1; + records->tail ().lastGlyphIndex = 0; bitmap_size_context->size += IndexSubtableRecord::min_size; c->serializer->push (); - if (unlikely (!add_new_subtable (c, bitmap_size_context, &((*records)[records->length - 1]), lookup, base, start))) + if (unlikely (!add_new_subtable (c, bitmap_size_context, &(records->tail ()), lookup, base, start))) { c->serializer->pop_discard (); c->serializer->revert (snap); @@ -504,8 +509,8 @@ struct IndexSubtableRecord return num_missing; } - bool get_extents (hb_glyph_extents_t *extents, const void *base) const - { return (base+offsetToSubtable).get_extents (extents); } + bool get_extents (hb_glyph_extents_t *extents, const void *base, bool scale) const + { return (base+offsetToSubtable).get_extents (extents, scale); } bool get_image_data (unsigned int gid, const void *base, @@ -541,7 +546,8 @@ struct IndexSubtableArray const IndexSubtableRecord*>> *lookup /* OUT */) const { bool start_glyph_is_set = false; - for (hb_codepoint_t new_gid = 0; new_gid < c->plan->num_output_glyphs (); new_gid++) + unsigned num_glyphs = c->plan->num_output_glyphs (); + for (hb_codepoint_t new_gid = 0; new_gid < num_glyphs; new_gid++) { hb_codepoint_t old_gid; if (unlikely (!c->plan->old_gid_for_new_gid (new_gid, &old_gid))) continue; @@ -572,9 +578,6 @@ struct IndexSubtableArray { TRACE_SUBSET (this); - auto *dst = c->serializer->start_embed (); - if (unlikely (!dst)) return_trace (false); - hb_vector_t> lookup; build_lookup (c, bitmap_size_context, &lookup); if (unlikely (!c->serializer->propagate_error (lookup))) @@ -634,6 +637,7 @@ struct BitmapSizeTable { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && + hb_barrier () && indexSubtableArrayOffset.sanitize (c, base, numberOfIndexSubtables) && horizontal.sanitize (c) && vertical.sanitize (c)); @@ -737,7 +741,9 @@ struct CBLC { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && + hb_barrier () && likely (version.major == 2 || version.major == 3) && + hb_barrier () && sizeTables.sanitize (c, this)); } @@ -833,7 +839,7 @@ struct CBDT } bool - get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const + get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents, bool scale = true) const { const void *base; const BitmapSizeTable &strike = this->cblc->choose_strike (font); @@ -841,7 +847,7 @@ struct CBDT if (!subtable_record || !strike.ppemX || !strike.ppemY) return false; - if (subtable_record->get_extents (extents, base)) + if (subtable_record->get_extents (extents, base, scale)) return true; unsigned int image_offset = 0, image_length = 0, image_format = 0; @@ -858,26 +864,29 @@ struct CBDT if (unlikely (image_length < GlyphBitmapDataFormat17::min_size)) return false; auto &glyphFormat17 = StructAtOffset (this->cbdt, image_offset); - glyphFormat17.glyphMetrics.get_extents (font, extents); + glyphFormat17.glyphMetrics.get_extents (font, extents, scale); break; } case 18: { if (unlikely (image_length < GlyphBitmapDataFormat18::min_size)) return false; auto &glyphFormat18 = StructAtOffset (this->cbdt, image_offset); - glyphFormat18.glyphMetrics.get_extents (font, extents); + glyphFormat18.glyphMetrics.get_extents (font, extents, scale); break; } default: return false; /* TODO: Support other image formats. */ } /* Convert to font units. */ - float x_scale = upem / (float) strike.ppemX; - float y_scale = upem / (float) strike.ppemY; - extents->x_bearing = roundf (extents->x_bearing * x_scale); - extents->y_bearing = roundf (extents->y_bearing * y_scale); - extents->width = roundf (extents->width * x_scale); - extents->height = roundf (extents->height * y_scale); + if (scale) + { + float x_scale = upem / (float) strike.ppemX; + float y_scale = upem / (float) strike.ppemY; + extents->x_bearing = roundf (extents->x_bearing * x_scale); + extents->y_bearing = roundf (extents->y_bearing * y_scale); + extents->width = roundf (extents->width * x_scale); + extents->height = roundf (extents->height * y_scale); + } return true; } @@ -934,6 +943,32 @@ struct CBDT 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 + { + hb_glyph_extents_t extents; + hb_glyph_extents_t pixel_extents; + hb_blob_t *blob = reference_png (font, glyph); + + if (unlikely (blob == hb_blob_get_empty ())) + return false; + + if (unlikely (!hb_font_get_glyph_extents (font, glyph, &extents))) + return false; + + if (unlikely (!get_extents (font, glyph, &pixel_extents, false))) + return false; + + bool ret = funcs->image (data, + blob, + pixel_extents.width, -pixel_extents.height, + HB_PAINT_IMAGE_FORMAT_PNG, + font->slant_xy, + &extents); + + hb_blob_destroy (blob); + return ret; + } + private: hb_blob_ptr_t cblc; hb_blob_ptr_t cbdt; @@ -945,6 +980,7 @@ struct CBDT { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && + hb_barrier () && likely (version.major == 2 || version.major == 3)); } @@ -960,12 +996,10 @@ CBLC::subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - auto *cblc_prime = c->serializer->start_embed (); - // Use a vector as a secondary buffer as the tables need to be built in parallel. hb_vector_t cbdt_prime; - if (unlikely (!cblc_prime)) return_trace (false); + auto *cblc_prime = c->serializer->start_embed (); if (unlikely (!c->serializer->extend_min (cblc_prime))) return_trace (false); cblc_prime->version = version; @@ -994,4 +1028,4 @@ struct CBDT_accelerator_t : CBDT::accelerator_t { } /* namespace OT */ -#endif /* HB_OT_COLOR_CBDT_TABLE_HH */ +#endif /* OT_COLOR_CBDT_CBDT_HH */ diff --git a/libs/harfbuzz/src/OT/Color/COLR/COLR.hh b/libs/harfbuzz/src/OT/Color/COLR/COLR.hh new file mode 100644 index 000000000..36b509d7c --- /dev/null +++ b/libs/harfbuzz/src/OT/Color/COLR/COLR.hh @@ -0,0 +1,2756 @@ +/* + * Copyright © 2018 Ebrahim Byagowi + * Copyright © 2020 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Calder Kitagawa + */ + +#ifndef OT_COLOR_COLR_COLR_HH +#define OT_COLOR_COLR_COLR_HH + +#include "../../../hb.hh" +#include "../../../hb-open-type.hh" +#include "../../../hb-ot-var-common.hh" +#include "../../../hb-paint.hh" +#include "../../../hb-paint-extents.hh" + +/* + * COLR -- Color + * https://docs.microsoft.com/en-us/typography/opentype/spec/colr + */ +#define HB_OT_TAG_COLR HB_TAG('C','O','L','R') + +namespace OT { +struct hb_paint_context_t; +} + +namespace OT { + +struct COLR; + +struct Paint; + +struct hb_paint_context_t : + hb_dispatch_context_t +{ + const char *get_name () { return "PAINT"; } + template + return_t dispatch (const T &obj) { obj.paint_glyph (this); return hb_empty_t (); } + static return_t default_return_value () { return hb_empty_t (); } + + const COLR* get_colr_table () const + { return reinterpret_cast (base); } + +public: + const void *base; + hb_paint_funcs_t *funcs; + void *data; + hb_font_t *font; + unsigned int palette_index; + hb_color_t foreground; + ItemVarStoreInstancer &instancer; + hb_map_t current_glyphs; + hb_map_t current_layers; + int depth_left = HB_MAX_NESTING_LEVEL; + int edge_count = HB_MAX_GRAPH_EDGE_COUNT; + + hb_paint_context_t (const void *base_, + hb_paint_funcs_t *funcs_, + void *data_, + hb_font_t *font_, + unsigned int palette_, + hb_color_t foreground_, + ItemVarStoreInstancer &instancer_) : + base (base_), + funcs (funcs_), + data (data_), + font (font_), + palette_index (palette_), + foreground (foreground_), + instancer (instancer_) + { } + + hb_color_t get_color (unsigned int color_index, float alpha, hb_bool_t *is_foreground) + { + hb_color_t color = foreground; + + *is_foreground = true; + + if (color_index != 0xffff) + { + if (!funcs->custom_palette_color (data, color_index, &color)) + { + unsigned int clen = 1; + hb_face_t *face = hb_font_get_face (font); + + hb_ot_color_palette_get_colors (face, palette_index, color_index, &clen, &color); + } + + *is_foreground = false; + } + + return HB_COLOR (hb_color_get_blue (color), + hb_color_get_green (color), + hb_color_get_red (color), + hb_color_get_alpha (color) * alpha); + } + + inline void recurse (const Paint &paint); +}; + +struct hb_colrv1_closure_context_t : + hb_dispatch_context_t +{ + template + return_t dispatch (const T &obj) + { + if (unlikely (nesting_level_left == 0)) + return hb_empty_t (); + + if (paint_visited (&obj)) + return hb_empty_t (); + + nesting_level_left--; + obj.closurev1 (this); + nesting_level_left++; + return hb_empty_t (); + } + static return_t default_return_value () { return hb_empty_t (); } + + bool paint_visited (const void *paint) + { + hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) paint - (uintptr_t) base); + if (visited_paint.in_error() || visited_paint.has (delta)) + return true; + + visited_paint.add (delta); + return false; + } + + const COLR* get_colr_table () const + { return reinterpret_cast (base); } + + void add_glyph (unsigned glyph_id) + { glyphs->add (glyph_id); } + + void add_layer_indices (unsigned first_layer_index, unsigned num_of_layers) + { layer_indices->add_range (first_layer_index, first_layer_index + num_of_layers - 1); } + + void add_palette_index (unsigned palette_index) + { palette_indices->add (palette_index); } + + void add_var_idxes (unsigned first_var_idx, unsigned num_idxes) + { + if (!num_idxes || first_var_idx == VarIdx::NO_VARIATION) return; + variation_indices->add_range (first_var_idx, first_var_idx + num_idxes - 1); + } + + public: + const void *base; + hb_set_t visited_paint; + hb_set_t *glyphs; + hb_set_t *layer_indices; + hb_set_t *palette_indices; + hb_set_t *variation_indices; + unsigned num_var_idxes; + unsigned nesting_level_left; + + hb_colrv1_closure_context_t (const void *base_, + hb_set_t *glyphs_, + hb_set_t *layer_indices_, + hb_set_t *palette_indices_, + hb_set_t *variation_indices_, + unsigned num_var_idxes_ = 1, + unsigned nesting_level_left_ = HB_MAX_NESTING_LEVEL) : + base (base_), + glyphs (glyphs_), + layer_indices (layer_indices_), + palette_indices (palette_indices_), + variation_indices (variation_indices_), + num_var_idxes (num_var_idxes_), + nesting_level_left (nesting_level_left_) + {} +}; + +struct LayerRecord +{ + operator hb_ot_color_layer_t () const { return {glyphId, colorIdx}; } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + public: + HBGlyphID16 glyphId; /* Glyph ID of layer glyph */ + Index colorIdx; /* Index value to use with a + * selected color palette. + * An index value of 0xFFFF + * is a special case indicating + * that the text foreground + * color (defined by a + * higher-level client) should + * be used and shall not be + * treated as actual index + * into CPAL ColorRecord array. */ + public: + DEFINE_SIZE_STATIC (4); +}; + +struct BaseGlyphRecord +{ + int cmp (hb_codepoint_t g) const + { return g < glyphId ? -1 : g > glyphId ? 1 : 0; } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + public: + HBGlyphID16 glyphId; /* Glyph ID of reference glyph */ + HBUINT16 firstLayerIdx; /* Index (from beginning of + * the Layer Records) to the + * layer record. There will be + * numLayers consecutive entries + * for this base glyph. */ + HBUINT16 numLayers; /* Number of color layers + * associated with this glyph */ + public: + DEFINE_SIZE_STATIC (6); +}; + +template +struct Variable +{ + static constexpr bool is_variable = true; + + Variable* copy (hb_serialize_context_t *c) const + { + TRACE_SERIALIZE (this); + return_trace (c->embed (this)); + } + + void closurev1 (hb_colrv1_closure_context_t* c) const + { + c->num_var_idxes = 0; + // update c->num_var_idxes during value closure + value.closurev1 (c); + c->add_var_idxes (varIdxBase, c->num_var_idxes); + } + + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer) const + { + TRACE_SUBSET (this); + if (!value.subset (c, instancer, varIdxBase)) return_trace (false); + if (c->plan->all_axes_pinned) + return_trace (true); + + VarIdx new_varidx; + new_varidx = varIdxBase; + if (varIdxBase != VarIdx::NO_VARIATION) + { + hb_pair_t *new_varidx_delta; + if (!c->plan->colrv1_variation_idx_delta_map.has (varIdxBase, &new_varidx_delta)) + return_trace (false); + + new_varidx = hb_first (*new_varidx_delta); + } + + return_trace (c->serializer->embed (new_varidx)); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && value.sanitize (c)); + } + + void paint_glyph (hb_paint_context_t *c) const + { + TRACE_PAINT (this); + value.paint_glyph (c, varIdxBase); + } + + void get_color_stop (hb_paint_context_t *c, + hb_color_stop_t *stop, + const ItemVarStoreInstancer &instancer) const + { + value.get_color_stop (c, stop, varIdxBase, instancer); + } + + hb_paint_extend_t get_extend () const + { + return value.get_extend (); + } + + protected: + T value; + public: + VarIdx varIdxBase; + public: + DEFINE_SIZE_MIN (VarIdx::static_size + T::min_size); +}; + +template +struct NoVariable +{ + static constexpr bool is_variable = false; + + static constexpr uint32_t varIdxBase = VarIdx::NO_VARIATION; + + NoVariable* copy (hb_serialize_context_t *c) const + { + TRACE_SERIALIZE (this); + return_trace (c->embed (this)); + } + + void closurev1 (hb_colrv1_closure_context_t* c) const + { value.closurev1 (c); } + + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer) const + { + TRACE_SUBSET (this); + return_trace (value.subset (c, instancer, varIdxBase)); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && value.sanitize (c)); + } + + void paint_glyph (hb_paint_context_t *c) const + { + TRACE_PAINT (this); + value.paint_glyph (c, varIdxBase); + } + + void get_color_stop (hb_paint_context_t *c, + hb_color_stop_t *stop, + const ItemVarStoreInstancer &instancer) const + { + value.get_color_stop (c, stop, VarIdx::NO_VARIATION, instancer); + } + + hb_paint_extend_t get_extend () const + { + return value.get_extend (); + } + + T value; + public: + DEFINE_SIZE_MIN (T::min_size); +}; + +// Color structures + +struct ColorStop +{ + void closurev1 (hb_colrv1_closure_context_t* c) const + { + c->add_palette_index (paletteIndex); + c->num_var_idxes = 2; + } + + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->stopOffset.set_float (stopOffset.to_float(instancer (varIdxBase, 0))); + out->alpha.set_float (alpha.to_float (instancer (varIdxBase, 1))); + } + + return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes.get (paletteIndex), + HB_SERIALIZE_ERROR_INT_OVERFLOW)); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + void get_color_stop (hb_paint_context_t *c, + hb_color_stop_t *out, + uint32_t varIdx, + const ItemVarStoreInstancer &instancer) const + { + out->offset = stopOffset.to_float(instancer (varIdx, 0)); + out->color = c->get_color (paletteIndex, + alpha.to_float (instancer (varIdx, 1)), + &out->is_foreground); + } + + F2DOT14 stopOffset; + HBUINT16 paletteIndex; + F2DOT14 alpha; + public: + DEFINE_SIZE_STATIC (2 + 2 * F2DOT14::static_size); +}; + +struct Extend : HBUINT8 +{ + enum { + EXTEND_PAD = 0, + EXTEND_REPEAT = 1, + EXTEND_REFLECT = 2, + }; + public: + DEFINE_SIZE_STATIC (1); +}; + +template class Var> +struct ColorLine +{ + void closurev1 (hb_colrv1_closure_context_t* c) const + { + for (const auto &stop : stops.iter ()) + stop.closurev1 (c); + } + + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + + if (!c->serializer->check_assign (out->extend, extend, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false); + if (!c->serializer->check_assign (out->stops.len, stops.len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW)) return_trace (false); + + for (const auto& stop : stops.iter ()) + { + if (!stop.subset (c, instancer)) return_trace (false); + } + return_trace (true); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + stops.sanitize (c)); + } + + /* get up to count stops from start */ + unsigned int + get_color_stops (hb_paint_context_t *c, + unsigned int start, + unsigned int *count, + hb_color_stop_t *color_stops, + const ItemVarStoreInstancer &instancer) const + { + unsigned int len = stops.len; + + if (count && color_stops) + { + unsigned int i; + for (i = 0; i < *count && start + i < len; i++) + stops[start + i].get_color_stop (c, &color_stops[i], instancer); + *count = i; + } + + return len; + } + + HB_INTERNAL static unsigned int static_get_color_stops (hb_color_line_t *color_line, + void *color_line_data, + unsigned int start, + unsigned int *count, + hb_color_stop_t *color_stops, + void *user_data) + { + const ColorLine *thiz = (const ColorLine *) color_line_data; + hb_paint_context_t *c = (hb_paint_context_t *) user_data; + return thiz->get_color_stops (c, start, count, color_stops, c->instancer); + } + + hb_paint_extend_t get_extend () const + { + return (hb_paint_extend_t) (unsigned int) extend; + } + + HB_INTERNAL static hb_paint_extend_t static_get_extend (hb_color_line_t *color_line, + void *color_line_data, + void *user_data) + { + const ColorLine *thiz = (const ColorLine *) color_line_data; + return thiz->get_extend (); + } + + Extend extend; + Array16Of> stops; + public: + DEFINE_SIZE_ARRAY_SIZED (3, stops); +}; + +// Composition modes + +// Compositing modes are taken from https://www.w3.org/TR/compositing-1/ +// NOTE: a brief audit of major implementations suggests most support most +// or all of the specified modes. +struct CompositeMode : HBUINT8 +{ + enum { + // Porter-Duff modes + // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators + COMPOSITE_CLEAR = 0, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_clear + COMPOSITE_SRC = 1, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_src + COMPOSITE_DEST = 2, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dst + COMPOSITE_SRC_OVER = 3, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcover + COMPOSITE_DEST_OVER = 4, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstover + COMPOSITE_SRC_IN = 5, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcin + COMPOSITE_DEST_IN = 6, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstin + COMPOSITE_SRC_OUT = 7, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcout + COMPOSITE_DEST_OUT = 8, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstout + COMPOSITE_SRC_ATOP = 9, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcatop + COMPOSITE_DEST_ATOP = 10, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstatop + COMPOSITE_XOR = 11, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_xor + COMPOSITE_PLUS = 12, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_plus + + // Blend modes + // https://www.w3.org/TR/compositing-1/#blending + COMPOSITE_SCREEN = 13, // https://www.w3.org/TR/compositing-1/#blendingscreen + COMPOSITE_OVERLAY = 14, // https://www.w3.org/TR/compositing-1/#blendingoverlay + COMPOSITE_DARKEN = 15, // https://www.w3.org/TR/compositing-1/#blendingdarken + COMPOSITE_LIGHTEN = 16, // https://www.w3.org/TR/compositing-1/#blendinglighten + COMPOSITE_COLOR_DODGE = 17, // https://www.w3.org/TR/compositing-1/#blendingcolordodge + COMPOSITE_COLOR_BURN = 18, // https://www.w3.org/TR/compositing-1/#blendingcolorburn + COMPOSITE_HARD_LIGHT = 19, // https://www.w3.org/TR/compositing-1/#blendinghardlight + COMPOSITE_SOFT_LIGHT = 20, // https://www.w3.org/TR/compositing-1/#blendingsoftlight + COMPOSITE_DIFFERENCE = 21, // https://www.w3.org/TR/compositing-1/#blendingdifference + COMPOSITE_EXCLUSION = 22, // https://www.w3.org/TR/compositing-1/#blendingexclusion + COMPOSITE_MULTIPLY = 23, // https://www.w3.org/TR/compositing-1/#blendingmultiply + + // Modes that, uniquely, do not operate on components + // https://www.w3.org/TR/compositing-1/#blendingnonseparable + COMPOSITE_HSL_HUE = 24, // https://www.w3.org/TR/compositing-1/#blendinghue + COMPOSITE_HSL_SATURATION = 25, // https://www.w3.org/TR/compositing-1/#blendingsaturation + COMPOSITE_HSL_COLOR = 26, // https://www.w3.org/TR/compositing-1/#blendingcolor + COMPOSITE_HSL_LUMINOSITY = 27, // https://www.w3.org/TR/compositing-1/#blendingluminosity + }; + public: + DEFINE_SIZE_STATIC (1); +}; + +struct Affine2x3 +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + void closurev1 (hb_colrv1_closure_context_t* c) const + { c->num_var_idxes = 6; } + + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->xx.set_float (xx.to_float(instancer (varIdxBase, 0))); + out->yx.set_float (yx.to_float(instancer (varIdxBase, 1))); + out->xy.set_float (xy.to_float(instancer (varIdxBase, 2))); + out->yy.set_float (yy.to_float(instancer (varIdxBase, 3))); + out->dx.set_float (dx.to_float(instancer (varIdxBase, 4))); + out->dy.set_float (dy.to_float(instancer (varIdxBase, 5))); + } + return_trace (true); + } + + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + TRACE_PAINT (this); + c->funcs->push_transform (c->data, + xx.to_float (c->instancer (varIdxBase, 0)), + yx.to_float (c->instancer (varIdxBase, 1)), + xy.to_float (c->instancer (varIdxBase, 2)), + yy.to_float (c->instancer (varIdxBase, 3)), + dx.to_float (c->instancer (varIdxBase, 4)), + dy.to_float (c->instancer (varIdxBase, 5))); + } + + F16DOT16 xx; + F16DOT16 yx; + F16DOT16 xy; + F16DOT16 yy; + F16DOT16 dx; + F16DOT16 dy; + public: + DEFINE_SIZE_STATIC (6 * F16DOT16::static_size); +}; + +struct PaintColrLayers +{ + void closurev1 (hb_colrv1_closure_context_t* c) const; + + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer HB_UNUSED) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + return_trace (c->serializer->check_assign (out->firstLayerIndex, c->plan->colrv1_layers.get (firstLayerIndex), + HB_SERIALIZE_ERROR_INT_OVERFLOW)); + + return_trace (true); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + inline void paint_glyph (hb_paint_context_t *c) const; + + HBUINT8 format; /* format = 1 */ + HBUINT8 numLayers; + HBUINT32 firstLayerIndex; /* index into COLRv1::layerList */ + public: + DEFINE_SIZE_STATIC (6); +}; + +struct PaintSolid +{ + void closurev1 (hb_colrv1_closure_context_t* c) const + { + c->add_palette_index (paletteIndex); + c->num_var_idxes = 1; + } + + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + out->alpha.set_float (alpha.to_float (instancer (varIdxBase, 0))); + + if (format == 3 && c->plan->all_axes_pinned) + out->format = 2; + + return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes.get (paletteIndex), + HB_SERIALIZE_ERROR_INT_OVERFLOW)); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + TRACE_PAINT (this); + hb_bool_t is_foreground; + hb_color_t color; + + color = c->get_color (paletteIndex, + alpha.to_float (c->instancer (varIdxBase, 0)), + &is_foreground); + c->funcs->color (c->data, is_foreground, color); + } + + HBUINT8 format; /* format = 2(noVar) or 3(Var)*/ + HBUINT16 paletteIndex; + F2DOT14 alpha; + public: + DEFINE_SIZE_STATIC (3 + F2DOT14::static_size); +}; + +template class Var> +struct PaintLinearGradient +{ + void closurev1 (hb_colrv1_closure_context_t* c) const + { + (this+colorLine).closurev1 (c); + c->num_var_idxes = 6; + } + + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->x0 = x0 + (int) roundf (instancer (varIdxBase, 0)); + out->y0 = y0 + (int) roundf (instancer (varIdxBase, 1)); + out->x1 = x1 + (int) roundf (instancer (varIdxBase, 2)); + out->y1 = y1 + (int) roundf (instancer (varIdxBase, 3)); + out->x2 = x2 + (int) roundf (instancer (varIdxBase, 4)); + out->y2 = y2 + (int) roundf (instancer (varIdxBase, 5)); + } + + if (format == 5 && c->plan->all_axes_pinned) + out->format = 4; + + return_trace (out->colorLine.serialize_subset (c, colorLine, this, instancer)); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && colorLine.sanitize (c, this)); + } + + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + TRACE_PAINT (this); + hb_color_line_t cl = { + (void *) &(this+colorLine), + (this+colorLine).static_get_color_stops, c, + (this+colorLine).static_get_extend, nullptr + }; + + c->funcs->linear_gradient (c->data, &cl, + x0 + c->instancer (varIdxBase, 0), + y0 + c->instancer (varIdxBase, 1), + x1 + c->instancer (varIdxBase, 2), + y1 + c->instancer (varIdxBase, 3), + x2 + c->instancer (varIdxBase, 4), + y2 + c->instancer (varIdxBase, 5)); + } + + HBUINT8 format; /* format = 4(noVar) or 5 (Var) */ + Offset24To> colorLine; /* Offset (from beginning of PaintLinearGradient + * table) to ColorLine subtable. */ + FWORD x0; + FWORD y0; + FWORD x1; + FWORD y1; + FWORD x2; + FWORD y2; + public: + DEFINE_SIZE_STATIC (4 + 6 * FWORD::static_size); +}; + +template class Var> +struct PaintRadialGradient +{ + void closurev1 (hb_colrv1_closure_context_t* c) const + { + (this+colorLine).closurev1 (c); + c->num_var_idxes = 6; + } + + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->x0 = x0 + (int) roundf (instancer (varIdxBase, 0)); + out->y0 = y0 + (int) roundf (instancer (varIdxBase, 1)); + out->radius0 = radius0 + (unsigned) roundf (instancer (varIdxBase, 2)); + out->x1 = x1 + (int) roundf (instancer (varIdxBase, 3)); + out->y1 = y1 + (int) roundf (instancer (varIdxBase, 4)); + out->radius1 = radius1 + (unsigned) roundf (instancer (varIdxBase, 5)); + } + + if (format == 7 && c->plan->all_axes_pinned) + out->format = 6; + + return_trace (out->colorLine.serialize_subset (c, colorLine, this, instancer)); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && colorLine.sanitize (c, this)); + } + + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + TRACE_PAINT (this); + hb_color_line_t cl = { + (void *) &(this+colorLine), + (this+colorLine).static_get_color_stops, c, + (this+colorLine).static_get_extend, nullptr + }; + + c->funcs->radial_gradient (c->data, &cl, + x0 + c->instancer (varIdxBase, 0), + y0 + c->instancer (varIdxBase, 1), + radius0 + c->instancer (varIdxBase, 2), + x1 + c->instancer (varIdxBase, 3), + y1 + c->instancer (varIdxBase, 4), + radius1 + c->instancer (varIdxBase, 5)); + } + + HBUINT8 format; /* format = 6(noVar) or 7 (Var) */ + Offset24To> colorLine; /* Offset (from beginning of PaintRadialGradient + * table) to ColorLine subtable. */ + FWORD x0; + FWORD y0; + UFWORD radius0; + FWORD x1; + FWORD y1; + UFWORD radius1; + public: + DEFINE_SIZE_STATIC (4 + 6 * FWORD::static_size); +}; + +template class Var> +struct PaintSweepGradient +{ + void closurev1 (hb_colrv1_closure_context_t* c) const + { + (this+colorLine).closurev1 (c); + c->num_var_idxes = 4; + } + + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->centerX = centerX + (int) roundf (instancer (varIdxBase, 0)); + out->centerY = centerY + (int) roundf (instancer (varIdxBase, 1)); + out->startAngle.set_float (startAngle.to_float (instancer (varIdxBase, 2))); + out->endAngle.set_float (endAngle.to_float (instancer (varIdxBase, 3))); + } + + if (format == 9 && c->plan->all_axes_pinned) + out->format = 8; + + return_trace (out->colorLine.serialize_subset (c, colorLine, this, instancer)); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && colorLine.sanitize (c, this)); + } + + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + TRACE_PAINT (this); + hb_color_line_t cl = { + (void *) &(this+colorLine), + (this+colorLine).static_get_color_stops, c, + (this+colorLine).static_get_extend, nullptr + }; + + c->funcs->sweep_gradient (c->data, &cl, + centerX + c->instancer (varIdxBase, 0), + centerY + c->instancer (varIdxBase, 1), + (startAngle.to_float (c->instancer (varIdxBase, 2)) + 1) * HB_PI, + (endAngle.to_float (c->instancer (varIdxBase, 3)) + 1) * HB_PI); + } + + HBUINT8 format; /* format = 8(noVar) or 9 (Var) */ + Offset24To> colorLine; /* Offset (from beginning of PaintSweepGradient + * table) to ColorLine subtable. */ + FWORD centerX; + FWORD centerY; + F2DOT14 startAngle; + F2DOT14 endAngle; + public: + DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size + 2 * F2DOT14::static_size); +}; + +// Paint a non-COLR glyph, filled as indicated by paint. +struct PaintGlyph +{ + void closurev1 (hb_colrv1_closure_context_t* c) const; + + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + + if (! c->serializer->check_assign (out->gid, c->plan->glyph_map->get (gid), + HB_SERIALIZE_ERROR_INT_OVERFLOW)) + return_trace (false); + + return_trace (out->paint.serialize_subset (c, paint, this, instancer)); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && paint.sanitize (c, this)); + } + + void paint_glyph (hb_paint_context_t *c) const + { + TRACE_PAINT (this); + c->funcs->push_inverse_root_transform (c->data, c->font); + c->funcs->push_clip_glyph (c->data, gid, 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); + c->funcs->pop_transform (c->data); + } + + HBUINT8 format; /* format = 10 */ + Offset24To paint; /* Offset (from beginning of PaintGlyph table) to Paint subtable. */ + HBUINT16 gid; + public: + DEFINE_SIZE_STATIC (6); +}; + +struct PaintColrGlyph +{ + void closurev1 (hb_colrv1_closure_context_t* c) const; + + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer HB_UNUSED) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + + return_trace (c->serializer->check_assign (out->gid, c->plan->glyph_map->get (gid), + HB_SERIALIZE_ERROR_INT_OVERFLOW)); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + inline void paint_glyph (hb_paint_context_t *c) const; + + HBUINT8 format; /* format = 11 */ + HBUINT16 gid; + public: + DEFINE_SIZE_STATIC (3); +}; + +template class Var> +struct PaintTransform +{ + HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; + + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + if (!out->transform.serialize_subset (c, transform, this, instancer)) return_trace (false); + if (format == 13 && c->plan->all_axes_pinned) + out->format = 12; + return_trace (out->src.serialize_subset (c, src, this, instancer)); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + src.sanitize (c, this) && + transform.sanitize (c, this)); + } + + void paint_glyph (hb_paint_context_t *c) const + { + TRACE_PAINT (this); + (this+transform).paint_glyph (c); + c->recurse (this+src); + c->funcs->pop_transform (c->data); + } + + HBUINT8 format; /* format = 12(noVar) or 13 (Var) */ + Offset24To src; /* Offset (from beginning of PaintTransform table) to Paint subtable. */ + Offset24To> transform; + public: + DEFINE_SIZE_STATIC (7); +}; + +struct PaintTranslate +{ + HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; + + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->dx = dx + (int) roundf (instancer (varIdxBase, 0)); + out->dy = dy + (int) roundf (instancer (varIdxBase, 1)); + } + + if (format == 15 && c->plan->all_axes_pinned) + out->format = 14; + + return_trace (out->src.serialize_subset (c, src, this, instancer)); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && src.sanitize (c, this)); + } + + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + TRACE_PAINT (this); + float ddx = dx + c->instancer (varIdxBase, 0); + float ddy = dy + c->instancer (varIdxBase, 1); + + bool p1 = c->funcs->push_translate (c->data, ddx, ddy); + c->recurse (this+src); + if (p1) c->funcs->pop_transform (c->data); + } + + HBUINT8 format; /* format = 14(noVar) or 15 (Var) */ + Offset24To src; /* Offset (from beginning of PaintTranslate table) to Paint subtable. */ + FWORD dx; + FWORD dy; + public: + DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size); +}; + +struct PaintScale +{ + HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; + + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->scaleX.set_float (scaleX.to_float (instancer (varIdxBase, 0))); + out->scaleY.set_float (scaleY.to_float (instancer (varIdxBase, 1))); + } + + if (format == 17 && c->plan->all_axes_pinned) + out->format = 16; + + return_trace (out->src.serialize_subset (c, src, this, instancer)); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && src.sanitize (c, this)); + } + + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + TRACE_PAINT (this); + float sx = scaleX.to_float (c->instancer (varIdxBase, 0)); + float sy = scaleY.to_float (c->instancer (varIdxBase, 1)); + + bool p1 = c->funcs->push_scale (c->data, sx, sy); + c->recurse (this+src); + if (p1) c->funcs->pop_transform (c->data); + } + + HBUINT8 format; /* format = 16 (noVar) or 17(Var) */ + Offset24To src; /* Offset (from beginning of PaintScale table) to Paint subtable. */ + F2DOT14 scaleX; + F2DOT14 scaleY; + public: + DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size); +}; + +struct PaintScaleAroundCenter +{ + HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; + + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->scaleX.set_float (scaleX.to_float (instancer (varIdxBase, 0))); + out->scaleY.set_float (scaleY.to_float (instancer (varIdxBase, 1))); + out->centerX = centerX + (int) roundf (instancer (varIdxBase, 2)); + out->centerY = centerY + (int) roundf (instancer (varIdxBase, 3)); + } + + if (format == 19 && c->plan->all_axes_pinned) + out->format = 18; + + return_trace (out->src.serialize_subset (c, src, this, instancer)); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && src.sanitize (c, this)); + } + + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + TRACE_PAINT (this); + float sx = scaleX.to_float (c->instancer (varIdxBase, 0)); + float sy = scaleY.to_float (c->instancer (varIdxBase, 1)); + float tCenterX = centerX + c->instancer (varIdxBase, 2); + float tCenterY = centerY + c->instancer (varIdxBase, 3); + + bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY); + bool p2 = c->funcs->push_scale (c->data, sx, sy); + bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY); + c->recurse (this+src); + if (p3) c->funcs->pop_transform (c->data); + if (p2) c->funcs->pop_transform (c->data); + if (p1) c->funcs->pop_transform (c->data); + } + + HBUINT8 format; /* format = 18 (noVar) or 19(Var) */ + Offset24To src; /* Offset (from beginning of PaintScaleAroundCenter table) to Paint subtable. */ + F2DOT14 scaleX; + F2DOT14 scaleY; + FWORD centerX; + FWORD centerY; + public: + DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size + 2 * FWORD::static_size); +}; + +struct PaintScaleUniform +{ + HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; + + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + out->scale.set_float (scale.to_float (instancer (varIdxBase, 0))); + + if (format == 21 && c->plan->all_axes_pinned) + out->format = 20; + + return_trace (out->src.serialize_subset (c, src, this, instancer)); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && src.sanitize (c, this)); + } + + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + TRACE_PAINT (this); + float s = scale.to_float (c->instancer (varIdxBase, 0)); + + bool p1 = c->funcs->push_scale (c->data, s, s); + c->recurse (this+src); + if (p1) c->funcs->pop_transform (c->data); + } + + HBUINT8 format; /* format = 20 (noVar) or 21(Var) */ + Offset24To src; /* Offset (from beginning of PaintScaleUniform table) to Paint subtable. */ + F2DOT14 scale; + public: + DEFINE_SIZE_STATIC (4 + F2DOT14::static_size); +}; + +struct PaintScaleUniformAroundCenter +{ + HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; + + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->scale.set_float (scale.to_float (instancer (varIdxBase, 0))); + out->centerX = centerX + (int) roundf (instancer (varIdxBase, 1)); + out->centerY = centerY + (int) roundf (instancer (varIdxBase, 2)); + } + + if (format == 23 && c->plan->all_axes_pinned) + out->format = 22; + + return_trace (out->src.serialize_subset (c, src, this, instancer)); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && src.sanitize (c, this)); + } + + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + TRACE_PAINT (this); + float s = scale.to_float (c->instancer (varIdxBase, 0)); + float tCenterX = centerX + c->instancer (varIdxBase, 1); + float tCenterY = centerY + c->instancer (varIdxBase, 2); + + bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY); + bool p2 = c->funcs->push_scale (c->data, s, s); + bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY); + c->recurse (this+src); + if (p3) c->funcs->pop_transform (c->data); + if (p2) c->funcs->pop_transform (c->data); + if (p1) c->funcs->pop_transform (c->data); + } + + HBUINT8 format; /* format = 22 (noVar) or 23(Var) */ + Offset24To src; /* Offset (from beginning of PaintScaleUniformAroundCenter table) to Paint subtable. */ + F2DOT14 scale; + FWORD centerX; + FWORD centerY; + public: + DEFINE_SIZE_STATIC (4 + F2DOT14::static_size + 2 * FWORD::static_size); +}; + +struct PaintRotate +{ + HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; + + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + out->angle.set_float (angle.to_float (instancer (varIdxBase, 0))); + + if (format == 25 && c->plan->all_axes_pinned) + out->format = 24; + + return_trace (out->src.serialize_subset (c, src, this, instancer)); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && src.sanitize (c, this)); + } + + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + TRACE_PAINT (this); + float a = angle.to_float (c->instancer (varIdxBase, 0)); + + bool p1 = c->funcs->push_rotate (c->data, a); + c->recurse (this+src); + if (p1) c->funcs->pop_transform (c->data); + } + + HBUINT8 format; /* format = 24 (noVar) or 25(Var) */ + Offset24To src; /* Offset (from beginning of PaintRotate table) to Paint subtable. */ + F2DOT14 angle; + public: + DEFINE_SIZE_STATIC (4 + F2DOT14::static_size); +}; + +struct PaintRotateAroundCenter +{ + HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; + + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->angle.set_float (angle.to_float (instancer (varIdxBase, 0))); + out->centerX = centerX + (int) roundf (instancer (varIdxBase, 1)); + out->centerY = centerY + (int) roundf (instancer (varIdxBase, 2)); + } + + if (format ==27 && c->plan->all_axes_pinned) + out->format = 26; + + return_trace (out->src.serialize_subset (c, src, this, instancer)); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && src.sanitize (c, this)); + } + + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + TRACE_PAINT (this); + float a = angle.to_float (c->instancer (varIdxBase, 0)); + float tCenterX = centerX + c->instancer (varIdxBase, 1); + float tCenterY = centerY + c->instancer (varIdxBase, 2); + + bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY); + bool p2 = c->funcs->push_rotate (c->data, a); + bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY); + c->recurse (this+src); + if (p3) c->funcs->pop_transform (c->data); + if (p2) c->funcs->pop_transform (c->data); + if (p1) c->funcs->pop_transform (c->data); + } + + HBUINT8 format; /* format = 26 (noVar) or 27(Var) */ + Offset24To src; /* Offset (from beginning of PaintRotateAroundCenter table) to Paint subtable. */ + F2DOT14 angle; + FWORD centerX; + FWORD centerY; + public: + DEFINE_SIZE_STATIC (4 + F2DOT14::static_size + 2 * FWORD::static_size); +}; + +struct PaintSkew +{ + HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; + + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->xSkewAngle.set_float (xSkewAngle.to_float (instancer (varIdxBase, 0))); + out->ySkewAngle.set_float (ySkewAngle.to_float (instancer (varIdxBase, 1))); + } + + if (format == 29 && c->plan->all_axes_pinned) + out->format = 28; + + return_trace (out->src.serialize_subset (c, src, this, instancer)); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && src.sanitize (c, this)); + } + + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + TRACE_PAINT (this); + float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0)); + float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1)); + + bool p1 = c->funcs->push_skew (c->data, sx, sy); + c->recurse (this+src); + if (p1) c->funcs->pop_transform (c->data); + } + + HBUINT8 format; /* format = 28(noVar) or 29 (Var) */ + Offset24To src; /* Offset (from beginning of PaintSkew table) to Paint subtable. */ + F2DOT14 xSkewAngle; + F2DOT14 ySkewAngle; + public: + DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size); +}; + +struct PaintSkewAroundCenter +{ + HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; + + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->xSkewAngle.set_float (xSkewAngle.to_float (instancer (varIdxBase, 0))); + out->ySkewAngle.set_float (ySkewAngle.to_float (instancer (varIdxBase, 1))); + out->centerX = centerX + (int) roundf (instancer (varIdxBase, 2)); + out->centerY = centerY + (int) roundf (instancer (varIdxBase, 3)); + } + + if (format == 31 && c->plan->all_axes_pinned) + out->format = 30; + + return_trace (out->src.serialize_subset (c, src, this, instancer)); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && src.sanitize (c, this)); + } + + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + TRACE_PAINT (this); + float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0)); + float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1)); + float tCenterX = centerX + c->instancer (varIdxBase, 2); + float tCenterY = centerY + c->instancer (varIdxBase, 3); + + bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY); + bool p2 = c->funcs->push_skew (c->data, sx, sy); + bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY); + c->recurse (this+src); + if (p3) c->funcs->pop_transform (c->data); + if (p2) c->funcs->pop_transform (c->data); + if (p1) c->funcs->pop_transform (c->data); + } + + HBUINT8 format; /* format = 30(noVar) or 31 (Var) */ + Offset24To src; /* Offset (from beginning of PaintSkewAroundCenter table) to Paint subtable. */ + F2DOT14 xSkewAngle; + F2DOT14 ySkewAngle; + FWORD centerX; + FWORD centerY; + public: + DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size + 2 * FWORD::static_size); +}; + +struct PaintComposite +{ + void closurev1 (hb_colrv1_closure_context_t* c) const; + + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + + bool ret = false; + ret |= out->src.serialize_subset (c, src, this, instancer); + ret |= out->backdrop.serialize_subset (c, backdrop, this, instancer); + return_trace (ret); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + c->check_ops (this->min_size) && // PainComposite can get exponential + src.sanitize (c, this) && + backdrop.sanitize (c, this)); + } + + void paint_glyph (hb_paint_context_t *c) const + { + TRACE_PAINT (this); + 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); + } + + HBUINT8 format; /* format = 32 */ + Offset24To src; /* Offset (from beginning of PaintComposite table) to source Paint subtable. */ + CompositeMode mode; /* If mode is unrecognized use COMPOSITE_CLEAR */ + Offset24To backdrop; /* Offset (from beginning of PaintComposite table) to backdrop Paint subtable. */ + public: + DEFINE_SIZE_STATIC (8); +}; + +struct ClipBoxData +{ + int xMin, yMin, xMax, yMax; +}; + +struct ClipBoxFormat1 +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + void get_clip_box (ClipBoxData &clip_box, const ItemVarStoreInstancer &instancer HB_UNUSED) const + { + clip_box.xMin = xMin; + clip_box.yMin = yMin; + clip_box.xMax = xMax; + clip_box.yMax = yMax; + } + + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->xMin = xMin + (int) roundf (instancer (varIdxBase, 0)); + out->yMin = yMin + (int) roundf (instancer (varIdxBase, 1)); + out->xMax = xMax + (int) roundf (instancer (varIdxBase, 2)); + out->yMax = yMax + (int) roundf (instancer (varIdxBase, 3)); + } + + if (format == 2 && c->plan->all_axes_pinned) + out->format = 1; + + return_trace (true); + } + + public: + HBUINT8 format; /* format = 1(noVar) or 2(Var)*/ + FWORD xMin; + FWORD yMin; + FWORD xMax; + FWORD yMax; + public: + DEFINE_SIZE_STATIC (1 + 4 * FWORD::static_size); +}; + +struct ClipBoxFormat2 : Variable +{ + void get_clip_box (ClipBoxData &clip_box, const ItemVarStoreInstancer &instancer) const + { + value.get_clip_box(clip_box, instancer); + if (instancer) + { + clip_box.xMin += roundf (instancer (varIdxBase, 0)); + clip_box.yMin += roundf (instancer (varIdxBase, 1)); + clip_box.xMax += roundf (instancer (varIdxBase, 2)); + clip_box.yMax += roundf (instancer (varIdxBase, 3)); + } + } + + void closurev1 (hb_colrv1_closure_context_t* c) const + { c->variation_indices->add_range (varIdxBase, varIdxBase + 3); } +}; + +struct ClipBox +{ + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer) const + { + TRACE_SUBSET (this); + switch (u.format) { + case 1: return_trace (u.format1.subset (c, instancer, VarIdx::NO_VARIATION)); + case 2: return_trace (u.format2.subset (c, instancer)); + default:return_trace (c->default_return_value ()); + } + } + + void closurev1 (hb_colrv1_closure_context_t* c) const + { + switch (u.format) { + case 2: u.format2.closurev1 (c); + default:return; + } + } + + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const + { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); + TRACE_DISPATCH (this, u.format); + switch (u.format) { + case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); + case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); + default:return_trace (c->default_return_value ()); + } + } + + bool get_extents (hb_glyph_extents_t *extents, + const ItemVarStoreInstancer &instancer) const + { + ClipBoxData clip_box; + switch (u.format) { + case 1: + u.format1.get_clip_box (clip_box, instancer); + break; + case 2: + u.format2.get_clip_box (clip_box, instancer); + break; + default: + return false; + } + + extents->x_bearing = clip_box.xMin; + extents->y_bearing = clip_box.yMax; + extents->width = clip_box.xMax - clip_box.xMin; + extents->height = clip_box.yMin - clip_box.yMax; + return true; + } + + protected: + union { + HBUINT8 format; /* Format identifier */ + ClipBoxFormat1 format1; + ClipBoxFormat2 format2; + } u; +}; + +struct ClipRecord +{ + int cmp (hb_codepoint_t g) const + { return g < startGlyphID ? -1 : g <= endGlyphID ? 0 : +1; } + + void closurev1 (hb_colrv1_closure_context_t* c, const void *base) const + { + if (!c->glyphs->intersects (startGlyphID, endGlyphID)) return; + (base+clipBox).closurev1 (c); + } + + bool subset (hb_subset_context_t *c, + const void *base, + const ItemVarStoreInstancer &instancer) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + + return_trace (out->clipBox.serialize_subset (c, clipBox, base, instancer)); + } + + bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && clipBox.sanitize (c, base)); + } + + bool get_extents (hb_glyph_extents_t *extents, + const void *base, + const ItemVarStoreInstancer &instancer) const + { + return (base+clipBox).get_extents (extents, instancer); + } + + public: + HBUINT16 startGlyphID; // first gid clip applies to + HBUINT16 endGlyphID; // last gid clip applies to, inclusive + Offset24To clipBox; // Box or VarBox + public: + DEFINE_SIZE_STATIC (7); +}; +DECLARE_NULL_NAMESPACE_BYTES (OT, ClipRecord); + +struct ClipList +{ + unsigned serialize_clip_records (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + const hb_set_t& gids, + const hb_map_t& gid_offset_map) const + { + TRACE_SERIALIZE (this); + if (gids.is_empty () || + gid_offset_map.get_population () != gids.get_population ()) + return_trace (0); + + unsigned count = 0; + + hb_codepoint_t start_gid= gids.get_min (); + hb_codepoint_t prev_gid = start_gid; + + unsigned offset = gid_offset_map.get (start_gid); + unsigned prev_offset = offset; + for (const hb_codepoint_t _ : gids.iter ()) + { + if (_ == start_gid) continue; + + offset = gid_offset_map.get (_); + if (_ == prev_gid + 1 && offset == prev_offset) + { + prev_gid = _; + continue; + } + + ClipRecord record; + record.startGlyphID = start_gid; + record.endGlyphID = prev_gid; + record.clipBox = prev_offset; + + if (!record.subset (c, this, instancer)) return_trace (0); + count++; + + start_gid = _; + prev_gid = _; + prev_offset = offset; + } + + //last one + { + ClipRecord record; + record.startGlyphID = start_gid; + record.endGlyphID = prev_gid; + record.clipBox = prev_offset; + if (!record.subset (c, this, instancer)) return_trace (0); + count++; + } + return_trace (count); + } + + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + if (!c->serializer->check_assign (out->format, format, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false); + + const hb_set_t& glyphset = c->plan->_glyphset_colred; + const hb_map_t &glyph_map = *c->plan->glyph_map; + + hb_map_t new_gid_offset_map; + hb_set_t new_gids; + for (const ClipRecord& record : clips.iter ()) + { + unsigned start_gid = record.startGlyphID; + unsigned end_gid = record.endGlyphID; + for (unsigned gid = start_gid; gid <= end_gid; gid++) + { + if (!glyphset.has (gid) || !glyph_map.has (gid)) continue; + unsigned new_gid = glyph_map.get (gid); + new_gid_offset_map.set (new_gid, record.clipBox); + new_gids.add (new_gid); + } + } + + unsigned count = serialize_clip_records (c, instancer, new_gids, new_gid_offset_map); + if (!count) return_trace (false); + return_trace (c->serializer->check_assign (out->clips.len, count, HB_SERIALIZE_ERROR_INT_OVERFLOW)); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + // TODO Make a formatted struct! + return_trace (c->check_struct (this) && clips.sanitize (c, this)); + } + + bool + get_extents (hb_codepoint_t gid, + hb_glyph_extents_t *extents, + const ItemVarStoreInstancer &instancer) const + { + auto *rec = clips.as_array ().bsearch (gid); + if (rec) + { + rec->get_extents (extents, this, instancer); + return true; + } + return false; + } + + HBUINT8 format; // Set to 1. + SortedArray32Of clips; // Clip records, sorted by startGlyphID + public: + DEFINE_SIZE_ARRAY_SIZED (5, clips); +}; + +struct Paint +{ + + template + bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const + { + TRACE_SANITIZE (this); + + if (unlikely (!c->check_start_recursion (HB_MAX_NESTING_LEVEL))) + return_trace (c->no_dispatch_return_value ()); + + return_trace (c->end_recursion (this->dispatch (c, std::forward (ds)...))); + } + + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const + { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); + TRACE_DISPATCH (this, u.format); + switch (u.format) { + case 1: return_trace (c->dispatch (u.paintformat1, std::forward (ds)...)); + case 2: return_trace (c->dispatch (u.paintformat2, std::forward (ds)...)); + case 3: return_trace (c->dispatch (u.paintformat3, std::forward (ds)...)); + case 4: return_trace (c->dispatch (u.paintformat4, std::forward (ds)...)); + case 5: return_trace (c->dispatch (u.paintformat5, std::forward (ds)...)); + case 6: return_trace (c->dispatch (u.paintformat6, std::forward (ds)...)); + case 7: return_trace (c->dispatch (u.paintformat7, std::forward (ds)...)); + case 8: return_trace (c->dispatch (u.paintformat8, std::forward (ds)...)); + case 9: return_trace (c->dispatch (u.paintformat9, std::forward (ds)...)); + case 10: return_trace (c->dispatch (u.paintformat10, std::forward (ds)...)); + case 11: return_trace (c->dispatch (u.paintformat11, std::forward (ds)...)); + case 12: return_trace (c->dispatch (u.paintformat12, std::forward (ds)...)); + case 13: return_trace (c->dispatch (u.paintformat13, std::forward (ds)...)); + case 14: return_trace (c->dispatch (u.paintformat14, std::forward (ds)...)); + case 15: return_trace (c->dispatch (u.paintformat15, std::forward (ds)...)); + case 16: return_trace (c->dispatch (u.paintformat16, std::forward (ds)...)); + case 17: return_trace (c->dispatch (u.paintformat17, std::forward (ds)...)); + case 18: return_trace (c->dispatch (u.paintformat18, std::forward (ds)...)); + case 19: return_trace (c->dispatch (u.paintformat19, std::forward (ds)...)); + case 20: return_trace (c->dispatch (u.paintformat20, std::forward (ds)...)); + case 21: return_trace (c->dispatch (u.paintformat21, std::forward (ds)...)); + case 22: return_trace (c->dispatch (u.paintformat22, std::forward (ds)...)); + case 23: return_trace (c->dispatch (u.paintformat23, std::forward (ds)...)); + case 24: return_trace (c->dispatch (u.paintformat24, std::forward (ds)...)); + case 25: return_trace (c->dispatch (u.paintformat25, std::forward (ds)...)); + case 26: return_trace (c->dispatch (u.paintformat26, std::forward (ds)...)); + case 27: return_trace (c->dispatch (u.paintformat27, std::forward (ds)...)); + case 28: return_trace (c->dispatch (u.paintformat28, std::forward (ds)...)); + case 29: return_trace (c->dispatch (u.paintformat29, std::forward (ds)...)); + case 30: return_trace (c->dispatch (u.paintformat30, std::forward (ds)...)); + case 31: return_trace (c->dispatch (u.paintformat31, std::forward (ds)...)); + case 32: return_trace (c->dispatch (u.paintformat32, std::forward (ds)...)); + default:return_trace (c->default_return_value ()); + } + } + + protected: + union { + HBUINT8 format; + PaintColrLayers paintformat1; + NoVariable paintformat2; + Variable paintformat3; + NoVariable> paintformat4; + Variable> paintformat5; + NoVariable> paintformat6; + Variable> paintformat7; + NoVariable> paintformat8; + Variable> paintformat9; + PaintGlyph paintformat10; + PaintColrGlyph paintformat11; + PaintTransform paintformat12; + PaintTransform paintformat13; + NoVariable paintformat14; + Variable paintformat15; + NoVariable paintformat16; + Variable paintformat17; + NoVariable paintformat18; + Variable paintformat19; + NoVariable paintformat20; + Variable paintformat21; + NoVariable paintformat22; + Variable paintformat23; + NoVariable paintformat24; + Variable paintformat25; + NoVariable paintformat26; + Variable paintformat27; + NoVariable paintformat28; + Variable paintformat29; + NoVariable paintformat30; + Variable paintformat31; + PaintComposite paintformat32; + } u; + public: + DEFINE_SIZE_MIN (2); +}; + +struct BaseGlyphPaintRecord +{ + int cmp (hb_codepoint_t g) const + { return g < glyphId ? -1 : g > glyphId ? 1 : 0; } + + bool serialize (hb_serialize_context_t *s, const hb_map_t* glyph_map, + const void* src_base, hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer) const + { + TRACE_SERIALIZE (this); + auto *out = s->embed (this); + if (unlikely (!out)) return_trace (false); + if (!s->check_assign (out->glyphId, glyph_map->get (glyphId), + HB_SERIALIZE_ERROR_INT_OVERFLOW)) + return_trace (false); + + return_trace (out->paint.serialize_subset (c, paint, src_base, instancer)); + } + + bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this) && paint.sanitize (c, base))); + } + + public: + HBGlyphID16 glyphId; /* Glyph ID of reference glyph */ + Offset32To paint; /* Offset (from beginning of BaseGlyphPaintRecord array) to Paint, + * Typically PaintColrLayers */ + public: + DEFINE_SIZE_STATIC (6); +}; + +struct BaseGlyphList : SortedArray32Of +{ + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + const hb_set_t* glyphset = &c->plan->_glyphset_colred; + + for (const auto& _ : as_array ()) + { + unsigned gid = _.glyphId; + if (!glyphset->has (gid)) continue; + + if (_.serialize (c->serializer, c->plan->glyph_map, this, c, instancer)) out->len++; + else return_trace (false); + } + + return_trace (out->len != 0); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (SortedArray32Of::sanitize (c, this)); + } +}; + +struct LayerList : Array32OfOffset32To +{ + const Paint& get_paint (unsigned i) const + { return this+(*this)[i]; } + + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + + bool ret = false; + for (const auto& _ : + hb_enumerate (*this) + | hb_filter (c->plan->colrv1_layers, hb_first)) + + { + auto *o = out->serialize_append (c->serializer); + if (unlikely (!o)) return_trace (false); + ret |= o->serialize_subset (c, _.second, this, instancer); + } + return_trace (ret); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (Array32OfOffset32To::sanitize (c, this)); + } +}; + +struct delta_set_index_map_subset_plan_t +{ + unsigned get_inner_bit_count () const { return inner_bit_count; } + unsigned get_width () const { return ((outer_bit_count + inner_bit_count + 7) / 8); } + hb_array_t get_output_map () const { return output_map.as_array (); } + + delta_set_index_map_subset_plan_t (const hb_map_t &new_deltaset_idx_varidx_map) + { + map_count = 0; + outer_bit_count = 0; + inner_bit_count = 1; + output_map.init (); + + /* search backwards */ + unsigned count = new_deltaset_idx_varidx_map.get_population (); + if (!count) return; + + unsigned last_idx = (unsigned)-1; + unsigned last_varidx = (unsigned)-1; + + for (unsigned i = count; i; i--) + { + unsigned delta_set_idx = i - 1; + unsigned var_idx = new_deltaset_idx_varidx_map.get (delta_set_idx); + if (i == count) + { + last_idx = delta_set_idx; + last_varidx = var_idx; + continue; + } + if (var_idx != last_varidx) + break; + last_idx = delta_set_idx; + } + + map_count = last_idx + 1; + } + + bool remap (const hb_map_t &new_deltaset_idx_varidx_map) + { + /* recalculate bit_count */ + outer_bit_count = 1; + inner_bit_count = 1; + + if (unlikely (!output_map.resize (map_count, false))) return false; + + for (unsigned idx = 0; idx < map_count; idx++) + { + uint32_t *var_idx; + if (!new_deltaset_idx_varidx_map.has (idx, &var_idx)) return false; + output_map.arrayZ[idx] = *var_idx; + + unsigned outer = (*var_idx) >> 16; + unsigned bit_count = (outer == 0) ? 1 : hb_bit_storage (outer); + outer_bit_count = hb_max (bit_count, outer_bit_count); + + unsigned inner = (*var_idx) & 0xFFFF; + bit_count = (inner == 0) ? 1 : hb_bit_storage (inner); + inner_bit_count = hb_max (bit_count, inner_bit_count); + } + return true; + } + + private: + unsigned map_count; + unsigned outer_bit_count; + unsigned inner_bit_count; + hb_vector_t output_map; +}; + +struct COLR +{ + static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR; + + bool has_v0_data () const { return numBaseGlyphs; } + bool has_v1_data () const + { + if (version < 1) + return false; + hb_barrier (); + + return (this+baseGlyphList).len > 0; + } + + unsigned int get_glyph_layers (hb_codepoint_t glyph, + unsigned int start_offset, + unsigned int *count, /* IN/OUT. May be NULL. */ + hb_ot_color_layer_t *layers /* OUT. May be NULL. */) const + { + const BaseGlyphRecord &record = (this+baseGlyphsZ).bsearch (numBaseGlyphs, glyph); + + hb_array_t all_layers = (this+layersZ).as_array (numLayers); + hb_array_t glyph_layers = all_layers.sub_array (record.firstLayerIdx, + record.numLayers); + if (count) + { + + glyph_layers.sub_array (start_offset, count) + | hb_sink (hb_array (layers, *count)) + ; + } + return glyph_layers.length; + } + + struct accelerator_t + { + accelerator_t (hb_face_t *face) + { colr = hb_sanitize_context_t ().reference_table (face); } + ~accelerator_t () { this->colr.destroy (); } + + bool is_valid () { return colr.get_blob ()->length; } + + void closure_glyphs (hb_codepoint_t glyph, + hb_set_t *related_ids /* OUT */) const + { colr->closure_glyphs (glyph, related_ids); } + + void closure_V0palette_indices (const hb_set_t *glyphs, + hb_set_t *palettes /* OUT */) const + { colr->closure_V0palette_indices (glyphs, palettes); } + + void closure_forV1 (hb_set_t *glyphset, + hb_set_t *layer_indices, + hb_set_t *palette_indices, + hb_set_t *variation_indices, + hb_set_t *delta_set_indices) const + { colr->closure_forV1 (glyphset, layer_indices, palette_indices, variation_indices, delta_set_indices); } + + bool has_var_store () const + { return colr->has_var_store (); } + + const ItemVariationStore &get_var_store () const + { return colr->get_var_store (); } + + bool has_delta_set_index_map () const + { return colr->has_delta_set_index_map (); } + + const DeltaSetIndexMap &get_delta_set_index_map () const + { return colr->get_delta_set_index_map (); } + + private: + hb_blob_ptr_t colr; + }; + + void closure_glyphs (hb_codepoint_t glyph, + hb_set_t *related_ids /* OUT */) const + { + const BaseGlyphRecord *record = get_base_glyph_record (glyph); + if (!record) return; + + auto glyph_layers = (this+layersZ).as_array (numLayers).sub_array (record->firstLayerIdx, + record->numLayers); + if (!glyph_layers.length) return; + related_ids->add_array (&glyph_layers[0].glyphId, glyph_layers.length, LayerRecord::min_size); + } + + void closure_V0palette_indices (const hb_set_t *glyphs, + hb_set_t *palettes /* OUT */) const + { + if (!numBaseGlyphs || !numLayers) return; + hb_array_t baseGlyphs = (this+baseGlyphsZ).as_array (numBaseGlyphs); + hb_array_t all_layers = (this+layersZ).as_array (numLayers); + + for (const BaseGlyphRecord record : baseGlyphs) + { + if (!glyphs->has (record.glyphId)) continue; + hb_array_t glyph_layers = all_layers.sub_array (record.firstLayerIdx, + record.numLayers); + for (const LayerRecord layer : glyph_layers) + palettes->add (layer.colorIdx); + } + } + + void closure_forV1 (hb_set_t *glyphset, + hb_set_t *layer_indices, + hb_set_t *palette_indices, + hb_set_t *variation_indices, + hb_set_t *delta_set_indices) const + { + if (version < 1) return; + hb_barrier (); + + hb_set_t visited_glyphs; + + hb_colrv1_closure_context_t c (this, &visited_glyphs, layer_indices, palette_indices, variation_indices); + const BaseGlyphList &baseglyph_paintrecords = this+baseGlyphList; + + for (const BaseGlyphPaintRecord &baseglyph_paintrecord: baseglyph_paintrecords.iter ()) + { + unsigned gid = baseglyph_paintrecord.glyphId; + if (!glyphset->has (gid)) continue; + + const Paint &paint = &baseglyph_paintrecords+baseglyph_paintrecord.paint; + paint.dispatch (&c); + } + hb_set_union (glyphset, &visited_glyphs); + + const ClipList &cliplist = this+clipList; + c.glyphs = glyphset; + for (const ClipRecord &clip_record : cliplist.clips.iter()) + clip_record.closurev1 (&c, &cliplist); + + // if a DeltaSetIndexMap is included, collected variation indices are + // actually delta set indices, we need to map them into variation indices + if (has_delta_set_index_map ()) + { + const DeltaSetIndexMap &var_idx_map = this+varIdxMap; + delta_set_indices->set (*variation_indices); + variation_indices->clear (); + for (unsigned delta_set_idx : *delta_set_indices) + variation_indices->add (var_idx_map.map (delta_set_idx)); + } + } + + const LayerList& get_layerList () const + { return (this+layerList); } + + const BaseGlyphList& get_baseglyphList () const + { return (this+baseGlyphList); } + + bool has_var_store () const + { return version >= 1 && hb_barrier () && varStore != 0; } + + bool has_delta_set_index_map () const + { return version >= 1 && hb_barrier () && varIdxMap != 0; } + + bool has_clip_list () const + { return version >= 1 && hb_barrier () && clipList != 0; } + + const DeltaSetIndexMap &get_delta_set_index_map () const + { return has_delta_set_index_map () && hb_barrier () ? this+varIdxMap : Null (DeltaSetIndexMap); } + + const ItemVariationStore &get_var_store () const + { return has_var_store () && hb_barrier () ? this+varStore : Null (ItemVariationStore); } + + const ClipList &get_clip_list () const + { return has_clip_list () && hb_barrier () ? this+clipList : Null (ClipList); } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + hb_barrier () && + (this+baseGlyphsZ).sanitize (c, numBaseGlyphs) && + (this+layersZ).sanitize (c, numLayers) && + (version == 0 || + (hb_barrier () && + baseGlyphList.sanitize (c, this) && + layerList.sanitize (c, this) && + clipList.sanitize (c, this) && + varIdxMap.sanitize (c, this) && + varStore.sanitize (c, this)))); + } + + template + bool serialize_V0 (hb_serialize_context_t *c, + unsigned version, + BaseIterator base_it, + LayerIterator layer_it) + { + TRACE_SERIALIZE (this); + if (unlikely (base_it.len () != layer_it.len ())) + return_trace (false); + + this->version = version; + numLayers = 0; + numBaseGlyphs = base_it.len (); + if (numBaseGlyphs == 0) + { + baseGlyphsZ = 0; + layersZ = 0; + return_trace (true); + } + + c->push (); + for (const hb_item_type _ : + base_it.iter ()) + { + auto* record = c->embed (_); + if (unlikely (!record)) return_trace (false); + record->firstLayerIdx = numLayers; + numLayers += record->numLayers; + } + c->add_link (baseGlyphsZ, c->pop_pack ()); + + c->push (); + for (const hb_item_type& _ : + layer_it.iter ()) + _.as_array ().copy (c); + + c->add_link (layersZ, c->pop_pack ()); + + return_trace (true); + } + + const BaseGlyphRecord* get_base_glyph_record (hb_codepoint_t gid) const + { + const BaseGlyphRecord* record = &(this+baseGlyphsZ).bsearch (numBaseGlyphs, (unsigned int) gid); + if (record == &Null (BaseGlyphRecord) || + (record && (hb_codepoint_t) record->glyphId != gid)) + record = nullptr; + return record; + } + + const BaseGlyphPaintRecord* get_base_glyph_paintrecord (hb_codepoint_t gid) const + { + const BaseGlyphPaintRecord* record = &(this+baseGlyphList).bsearch ((unsigned) gid); + if ((record && (hb_codepoint_t) record->glyphId != gid)) + record = nullptr; + return record; + } + + bool downgrade_to_V0 (const hb_set_t &glyphset) const + { + //no more COLRv1 glyphs, downgrade to version 0 + for (const BaseGlyphPaintRecord& _ : get_baseglyphList ()) + if (glyphset.has (_.glyphId)) + return false; + + return true; + } + + bool subset_varstore (hb_subset_context_t *c, + COLR* out /* OUT */) const + { + TRACE_SUBSET (this); + if (!varStore || c->plan->all_axes_pinned || + !c->plan->colrv1_variation_idx_delta_map) + return_trace (true); + + const ItemVariationStore& var_store = this+varStore; + if (c->plan->normalized_coords) + { + item_variations_t item_vars; + /* turn off varstore optimization when varIdxMap is null, so we maintain + * original var_idx sequence */ + bool optimize = (varIdxMap != 0) ? true : false; + if (!item_vars.instantiate (var_store, c->plan, + optimize, /* optimization */ + optimize, /* use_no_variation_idx = false */ + c->plan->colrv1_varstore_inner_maps.as_array ())) + return_trace (false); + + /* do not serialize varStore if there's no variation data after + * instancing: region_list or var_data is empty */ + if (item_vars.get_region_list () && + item_vars.get_vardata_encodings () && + !out->varStore.serialize_serialize (c->serializer, + item_vars.has_long_word (), + c->plan->axis_tags, + item_vars.get_region_list (), + item_vars.get_vardata_encodings ())) + return_trace (false); + + /* if varstore is optimized, update colrv1_new_deltaset_idx_varidx_map in + * subset plan. + * If varstore is empty after instancing, varidx_map would be empty and + * all var_idxes will be updated to VarIdx::NO_VARIATION */ + if (optimize) + { + const hb_map_t &varidx_map = item_vars.get_varidx_map (); + for (auto _ : c->plan->colrv1_new_deltaset_idx_varidx_map.iter_ref ()) + { + uint32_t varidx = _.second; + uint32_t *new_varidx; + if (varidx_map.has (varidx, &new_varidx)) + _.second = *new_varidx; + else + _.second = VarIdx::NO_VARIATION; + } + } + } + else + { + if (unlikely (!out->varStore.serialize_serialize (c->serializer, + &var_store, + c->plan->colrv1_varstore_inner_maps.as_array ()))) + return_trace (false); + } + + return_trace (true); + } + + bool subset_delta_set_index_map (hb_subset_context_t *c, + COLR* out /* OUT */) const + { + TRACE_SUBSET (this); + if (!varIdxMap || c->plan->all_axes_pinned || + !c->plan->colrv1_new_deltaset_idx_varidx_map) + return_trace (true); + + const hb_map_t &deltaset_idx_varidx_map = c->plan->colrv1_new_deltaset_idx_varidx_map; + delta_set_index_map_subset_plan_t index_map_plan (deltaset_idx_varidx_map); + + if (unlikely (!index_map_plan.remap (deltaset_idx_varidx_map))) + return_trace (false); + + return_trace (out->varIdxMap.serialize_serialize (c->serializer, index_map_plan)); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map; + const hb_set_t& glyphset = c->plan->_glyphset_colred; + + auto base_it = + + hb_range (c->plan->num_output_glyphs ()) + | hb_filter ([&](hb_codepoint_t new_gid) + { + hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid); + if (glyphset.has (old_gid)) return true; + return false; + }) + | hb_map_retains_sorting ([&](hb_codepoint_t new_gid) + { + hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid); + + const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid); + if (unlikely (!old_record)) + return hb_pair_t (false, Null (BaseGlyphRecord)); + BaseGlyphRecord new_record = {}; + new_record.glyphId = new_gid; + new_record.numLayers = old_record->numLayers; + return hb_pair_t (true, new_record); + }) + | hb_filter (hb_first) + | hb_map_retains_sorting (hb_second) + ; + + auto layer_it = + + hb_range (c->plan->num_output_glyphs ()) + | hb_map (reverse_glyph_map) + | hb_filter (glyphset) + | hb_map_retains_sorting ([&](hb_codepoint_t old_gid) + { + const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid); + hb_vector_t out_layers; + + if (unlikely (!old_record || + old_record->firstLayerIdx >= numLayers || + old_record->firstLayerIdx + old_record->numLayers > numLayers)) + return hb_pair_t> (false, out_layers); + + auto layers = (this+layersZ).as_array (numLayers).sub_array (old_record->firstLayerIdx, + old_record->numLayers); + out_layers.resize (layers.length); + for (unsigned int i = 0; i < layers.length; i++) { + out_layers[i] = layers[i]; + hb_codepoint_t new_gid = 0; + if (unlikely (!c->plan->new_gid_for_old_gid (out_layers[i].glyphId, &new_gid))) + return hb_pair_t> (false, out_layers); + out_layers[i].glyphId = new_gid; + out_layers[i].colorIdx = c->plan->colr_palettes.get (layers[i].colorIdx); + } + + return hb_pair_t> (true, out_layers); + }) + | hb_filter (hb_first) + | hb_map_retains_sorting (hb_second) + ; + + if (version == 0 && (!base_it || !layer_it)) + return_trace (false); + + auto *colr_prime = c->serializer->start_embed (); + if (unlikely (!c->serializer->extend_min (colr_prime))) return_trace (false); + + if (version == 0 || downgrade_to_V0 (glyphset)) + return_trace (colr_prime->serialize_V0 (c->serializer, 0, base_it, layer_it)); + + hb_barrier (); + + //start version 1 + if (!c->serializer->allocate_size (5 * HBUINT32::static_size)) return_trace (false); + if (!colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it)) return_trace (false); + + /* subset ItemVariationStore first, cause varidx_map needs to be updated + * after instancing */ + if (!subset_varstore (c, colr_prime)) return_trace (false); + + ItemVarStoreInstancer instancer (&(get_var_store ()), + &(get_delta_set_index_map ()), + c->plan->normalized_coords.as_array ()); + + if (!colr_prime->baseGlyphList.serialize_subset (c, baseGlyphList, this, instancer)) + return_trace (false); + + colr_prime->layerList.serialize_subset (c, layerList, this, instancer); + colr_prime->clipList.serialize_subset (c, clipList, this, instancer); + + return_trace (subset_delta_set_index_map (c, colr_prime)); + } + + const Paint *get_base_glyph_paint (hb_codepoint_t glyph) const + { + const BaseGlyphList &baseglyph_paintrecords = this+baseGlyphList; + const BaseGlyphPaintRecord* record = get_base_glyph_paintrecord (glyph); + if (record) + { + const Paint &paint = &baseglyph_paintrecords+record->paint; + return &paint; + } + else + return nullptr; + } + +#ifndef HB_NO_PAINT + bool + get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const + { + + ItemVarStoreInstancer instancer (&(get_var_store ()), + &(get_delta_set_index_map ()), + hb_array (font->coords, font->num_coords)); + + if (get_clip (glyph, extents, instancer)) + { + font->scale_glyph_extents (extents); + return true; + } + + auto *extents_funcs = hb_paint_extents_get_funcs (); + hb_paint_extents_context_t extents_data; + bool ret = paint_glyph (font, glyph, extents_funcs, &extents_data, 0, HB_COLOR(0,0,0,0)); + + hb_extents_t e = extents_data.get_extents (); + if (e.is_void ()) + { + extents->x_bearing = 0; + extents->y_bearing = 0; + extents->width = 0; + extents->height = 0; + } + else + { + extents->x_bearing = e.xmin; + extents->y_bearing = e.ymax; + extents->width = e.xmax - e.xmin; + extents->height = e.ymin - e.ymax; + } + + return ret; + } +#endif + + bool + has_paint_for_glyph (hb_codepoint_t glyph) const + { + if (version >= 1) + { + hb_barrier (); + + const Paint *paint = get_base_glyph_paint (glyph); + + return paint != nullptr; + } + + return false; + } + + bool get_clip (hb_codepoint_t glyph, + hb_glyph_extents_t *extents, + const ItemVarStoreInstancer instancer) const + { + return get_clip_list ().get_extents (glyph, + extents, + instancer); + } + +#ifndef HB_NO_PAINT + bool + paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, unsigned int palette_index, hb_color_t foreground, bool clip = true) const + { + ItemVarStoreInstancer instancer (&(get_var_store ()), + &(get_delta_set_index_map ()), + hb_array (font->coords, font->num_coords)); + hb_paint_context_t c (this, funcs, data, font, palette_index, foreground, instancer); + c.current_glyphs.add (glyph); + + if (version >= 1) + { + hb_barrier (); + + const Paint *paint = get_base_glyph_paint (glyph); + if (paint) + { + // COLRv1 glyph + + bool is_bounded = true; + if (clip) + { + hb_glyph_extents_t extents; + if (get_clip (glyph, &extents, instancer)) + { + font->scale_glyph_extents (&extents); + c.funcs->push_clip_rectangle (c.data, + extents.x_bearing, + extents.y_bearing + extents.height, + extents.x_bearing + extents.width, + extents.y_bearing); + } + else + { + auto *extents_funcs = hb_paint_extents_get_funcs (); + hb_paint_extents_context_t extents_data; + + paint_glyph (font, glyph, + extents_funcs, &extents_data, + palette_index, foreground, + false); + + hb_extents_t extents = extents_data.get_extents (); + is_bounded = extents_data.is_bounded (); + + c.funcs->push_clip_rectangle (c.data, + extents.xmin, + extents.ymin, + extents.xmax, + extents.ymax); + } + } + + c.funcs->push_root_transform (c.data, font); + + if (is_bounded) + c.recurse (*paint); + + c.funcs->pop_transform (c.data); + + if (clip) + c.funcs->pop_clip (c.data); + + return true; + } + } + + const BaseGlyphRecord *record = get_base_glyph_record (glyph); + if (record && ((hb_codepoint_t) record->glyphId == glyph)) + { + // COLRv0 glyph + for (const auto &r : (this+layersZ).as_array (numLayers) + .sub_array (record->firstLayerIdx, record->numLayers)) + { + hb_bool_t is_foreground; + hb_color_t color = c.get_color (r.colorIdx, 1., &is_foreground); + c.funcs->push_clip_glyph (c.data, r.glyphId, c.font); + c.funcs->color (c.data, is_foreground, color); + c.funcs->pop_clip (c.data); + } + + return true; + } + + return false; + } +#endif + + protected: + HBUINT16 version; /* Table version number (starts at 0). */ + HBUINT16 numBaseGlyphs; /* Number of Base Glyph Records. */ + NNOffset32To> + baseGlyphsZ; /* Offset to Base Glyph records. */ + NNOffset32To> + layersZ; /* Offset to Layer Records. */ + HBUINT16 numLayers; /* Number of Layer Records. */ + // Version-1 additions + Offset32To baseGlyphList; + Offset32To layerList; + Offset32To clipList; // Offset to ClipList table (may be NULL) + Offset32To varIdxMap; // Offset to DeltaSetIndexMap table (may be NULL) + Offset32To varStore; + public: + DEFINE_SIZE_MIN (14); +}; + +struct COLR_accelerator_t : COLR::accelerator_t { + COLR_accelerator_t (hb_face_t *face) : COLR::accelerator_t (face) {} +}; + +void +hb_paint_context_t::recurse (const Paint &paint) +{ + if (unlikely (depth_left <= 0 || edge_count <= 0)) return; + depth_left--; + edge_count--; + paint.dispatch (this); + depth_left++; +} + +void PaintColrLayers::paint_glyph (hb_paint_context_t *c) const +{ + TRACE_PAINT (this); + const LayerList &paint_offset_lists = c->get_colr_table ()->get_layerList (); + for (unsigned i = firstLayerIndex; i < firstLayerIndex + numLayers; i++) + { + if (unlikely (c->current_layers.has (i))) + continue; + + c->current_layers.add (i); + + const Paint &paint = paint_offset_lists.get_paint (i); + c->funcs->push_group (c->data); + c->recurse (paint); + c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER); + + c->current_layers.del (i); + } +} + +void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const +{ + TRACE_PAINT (this); + + if (unlikely (c->current_glyphs.has (gid))) + return; + + c->current_glyphs.add (gid); + + c->funcs->push_inverse_root_transform (c->data, c->font); + if (c->funcs->color_glyph (c->data, gid, c->font)) + { + c->funcs->pop_transform (c->data); + c->current_glyphs.del (gid); + return; + } + c->funcs->pop_transform (c->data); + + const COLR *colr_table = c->get_colr_table (); + const Paint *paint = colr_table->get_base_glyph_paint (gid); + + hb_glyph_extents_t extents = {0}; + bool has_clip_box = colr_table->get_clip (gid, &extents, c->instancer); + + if (has_clip_box) + c->funcs->push_clip_rectangle (c->data, + extents.x_bearing, + extents.y_bearing + extents.height, + extents.x_bearing + extents.width, + extents.y_bearing); + + if (paint) + c->recurse (*paint); + + if (has_clip_box) + c->funcs->pop_clip (c->data); + + c->current_glyphs.del (gid); +} + +} /* namespace OT */ + +#endif /* OT_COLOR_COLR_COLR_HH */ diff --git a/libs/harfbuzz/src/hb-ot-color-colrv1-closure.hh b/libs/harfbuzz/src/OT/Color/COLR/colrv1-closure.hh similarity index 81% rename from libs/harfbuzz/src/hb-ot-color-colrv1-closure.hh rename to libs/harfbuzz/src/OT/Color/COLR/colrv1-closure.hh index fbaf2ec26..9ed0aa563 100644 --- a/libs/harfbuzz/src/hb-ot-color-colrv1-closure.hh +++ b/libs/harfbuzz/src/OT/Color/COLR/colrv1-closure.hh @@ -24,12 +24,11 @@ * */ -#ifndef HB_OT_COLR_COLRV1_CLOSURE_HH -#define HB_OT_COLR_COLRV1_CLOSURE_HH +#ifndef OT_COLOR_COLR_COLRV1_CLOSURE_HH +#define OT_COLOR_COLR_COLRV1_CLOSURE_HH -#include "hb-open-type.hh" -#include "hb-ot-layout-common.hh" -#include "hb-ot-color-colr-table.hh" +#include "../../../hb-open-type.hh" +#include "COLR.hh" /* * COLR -- Color @@ -67,34 +66,64 @@ HB_INTERNAL void PaintColrGlyph::closurev1 (hb_colrv1_closure_context_t* c) cons template class Var> HB_INTERNAL void PaintTransform::closurev1 (hb_colrv1_closure_context_t* c) const -{ (this+src).dispatch (c); } +{ + (this+src).dispatch (c); + (this+transform).closurev1 (c); +} HB_INTERNAL void PaintTranslate::closurev1 (hb_colrv1_closure_context_t* c) const -{ (this+src).dispatch (c); } +{ + (this+src).dispatch (c); + c->num_var_idxes = 2; +} HB_INTERNAL void PaintScale::closurev1 (hb_colrv1_closure_context_t* c) const -{ (this+src).dispatch (c); } +{ + (this+src).dispatch (c); + c->num_var_idxes = 2; +} HB_INTERNAL void PaintScaleAroundCenter::closurev1 (hb_colrv1_closure_context_t* c) const -{ (this+src).dispatch (c); } +{ + (this+src).dispatch (c); + c->num_var_idxes = 4; +} HB_INTERNAL void PaintScaleUniform::closurev1 (hb_colrv1_closure_context_t* c) const -{ (this+src).dispatch (c); } +{ + (this+src).dispatch (c); + c->num_var_idxes = 1; +} HB_INTERNAL void PaintScaleUniformAroundCenter::closurev1 (hb_colrv1_closure_context_t* c) const -{ (this+src).dispatch (c); } +{ + (this+src).dispatch (c); + c->num_var_idxes = 3; +} HB_INTERNAL void PaintRotate::closurev1 (hb_colrv1_closure_context_t* c) const -{ (this+src).dispatch (c); } +{ + (this+src).dispatch (c); + c->num_var_idxes = 1; +} HB_INTERNAL void PaintRotateAroundCenter::closurev1 (hb_colrv1_closure_context_t* c) const -{ (this+src).dispatch (c); } +{ + (this+src).dispatch (c); + c->num_var_idxes = 3; +} HB_INTERNAL void PaintSkew::closurev1 (hb_colrv1_closure_context_t* c) const -{ (this+src).dispatch (c); } +{ + (this+src).dispatch (c); + c->num_var_idxes = 2; +} HB_INTERNAL void PaintSkewAroundCenter::closurev1 (hb_colrv1_closure_context_t* c) const -{ (this+src).dispatch (c); } +{ + (this+src).dispatch (c); + c->num_var_idxes = 4; +} HB_INTERNAL void PaintComposite::closurev1 (hb_colrv1_closure_context_t* c) const { @@ -105,4 +134,4 @@ HB_INTERNAL void PaintComposite::closurev1 (hb_colrv1_closure_context_t* c) cons } /* namespace OT */ -#endif /* HB_OT_COLR_COLRV1_CLOSURE_HH */ +#endif /* OT_COLOR_COLR_COLRV1_CLOSURE_HH */ diff --git a/libs/harfbuzz/src/hb-ot-color-cpal-table.hh b/libs/harfbuzz/src/OT/Color/CPAL/CPAL.hh similarity index 87% rename from libs/harfbuzz/src/hb-ot-color-cpal-table.hh rename to libs/harfbuzz/src/OT/Color/CPAL/CPAL.hh index bcab77f79..2821334db 100644 --- a/libs/harfbuzz/src/hb-ot-color-cpal-table.hh +++ b/libs/harfbuzz/src/OT/Color/CPAL/CPAL.hh @@ -25,12 +25,12 @@ * Google Author(s): Sascha Brawer */ -#ifndef HB_OT_COLOR_CPAL_TABLE_HH -#define HB_OT_COLOR_CPAL_TABLE_HH +#ifndef OT_COLOR_CPAL_CPAL_HH +#define OT_COLOR_CPAL_CPAL_HH -#include "hb-open-type.hh" -#include "hb-ot-color.h" -#include "hb-ot-name.h" +#include "../../../hb-open-type.hh" +#include "../../../hb-ot-color.h" +#include "../../../hb-ot-name.h" /* @@ -73,6 +73,30 @@ struct CPALV1Tail } public: + void collect_name_ids (const void *base, + unsigned palette_count, + unsigned color_count, + const hb_map_t *color_index_map, + hb_set_t *nameids_to_retain /* OUT */) const + { + if (paletteLabelsZ) + { + + (base+paletteLabelsZ).as_array (palette_count) + | hb_sink (nameids_to_retain) + ; + } + + if (colorLabelsZ) + { + const hb_array_t colorLabels = (base+colorLabelsZ).as_array (color_count); + for (unsigned i = 0; i < color_count; i++) + { + if (!color_index_map->has (i)) continue; + nameids_to_retain->add (colorLabels[i]); + } + } + } + bool serialize (hb_serialize_context_t *c, unsigned palette_count, unsigned color_count, @@ -95,13 +119,10 @@ struct CPALV1Tail if (colorLabelsZ) { c->push (); - for (const auto _ : colorLabels) + for (unsigned i = 0; i < color_count; i++) { - const hb_codepoint_t *v; - if (!color_index_map->has (_, &v)) continue; - NameID new_color_idx; - new_color_idx = *v; - if (!c->copy (new_color_idx)) + if (!color_index_map->has (i)) continue; + if (!c->copy (colorLabels[i])) { c->pop_discard (); return_trace (false); @@ -189,10 +210,21 @@ struct CPAL return numColors; } + void collect_name_ids (const hb_map_t *color_index_map, + hb_set_t *nameids_to_retain /* OUT */) const + { + if (version == 1) + { + hb_barrier (); + v1 ().collect_name_ids (this, numPalettes, numColors, color_index_map, nameids_to_retain); + } + } + private: const CPALV1Tail& v1 () const { if (version == 0) return Null (CPALV1Tail); + hb_barrier (); return StructAfter (*this); } @@ -239,7 +271,7 @@ struct CPAL TRACE_SUBSET (this); if (!numPalettes) return_trace (false); - const hb_map_t *color_index_map = c->plan->colr_palettes; + const hb_map_t *color_index_map = &c->plan->colr_palettes; if (color_index_map->is_empty ()) return_trace (false); hb_set_t retained_color_indices; @@ -284,7 +316,10 @@ struct CPAL return_trace (false); if (version == 1) + { + hb_barrier (); return_trace (v1 ().serialize (c->serializer, numPalettes, numColors, this, color_index_map)); + } return_trace (true); } @@ -293,6 +328,7 @@ struct CPAL { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && + hb_barrier () && (this+colorRecordsZ).sanitize (c, numColorRecords) && colorRecordIndicesZ.sanitize (c, numPalettes) && (version == 0 || v1 ().sanitize (c, this, numPalettes, numColors))); @@ -319,4 +355,4 @@ struct CPAL } /* namespace OT */ -#endif /* HB_OT_COLOR_CPAL_TABLE_HH */ +#endif /* OT_COLOR_CPAL_CPAL_HH */ diff --git a/libs/harfbuzz/src/hb-ot-color-sbix-table.hh b/libs/harfbuzz/src/OT/Color/sbix/sbix.hh similarity index 88% rename from libs/harfbuzz/src/hb-ot-color-sbix-table.hh rename to libs/harfbuzz/src/OT/Color/sbix/sbix.hh index d0e2235fb..51ae1a9c6 100644 --- a/libs/harfbuzz/src/hb-ot-color-sbix-table.hh +++ b/libs/harfbuzz/src/OT/Color/sbix/sbix.hh @@ -25,11 +25,11 @@ * Google Author(s): Calder Kitagawa */ -#ifndef HB_OT_COLOR_SBIX_TABLE_HH -#define HB_OT_COLOR_SBIX_TABLE_HH +#ifndef OT_COLOR_SBIX_SBIX_HH +#define OT_COLOR_SBIX_SBIX_HH -#include "hb-open-type.hh" -#include "hb-ot-layout-common.hh" +#include "../../../hb-open-type.hh" +#include "../../../hb-paint.hh" /* * sbix -- Standard Bitmap Graphics @@ -48,7 +48,6 @@ struct SBIXGlyph { TRACE_SERIALIZE (this); SBIXGlyph* new_glyph = c->start_embed (); - if (unlikely (!new_glyph)) return_trace (nullptr); if (unlikely (!c->extend_min (new_glyph))) return_trace (nullptr); new_glyph->xOffset = xOffset; @@ -143,7 +142,6 @@ struct SBIXStrike unsigned int num_output_glyphs = c->plan->num_output_glyphs (); auto* out = c->serializer->start_embed (); - if (unlikely (!out)) return_trace (false); auto snap = c->serializer->snapshot (); if (unlikely (!c->serializer->extend (out, num_output_glyphs + 1))) return_trace (false); out->ppem = ppem; @@ -213,10 +211,11 @@ struct sbix bool get_extents (hb_font_t *font, hb_codepoint_t glyph, - hb_glyph_extents_t *extents) const + hb_glyph_extents_t *extents, + bool scale = true) const { /* We only support PNG right now, and following function checks type. */ - return get_png_extents (font, glyph, extents); + return get_png_extents (font, glyph, extents, scale); } hb_blob_t *reference_png (hb_font_t *font, @@ -231,6 +230,37 @@ struct sbix num_glyphs, available_ppem); } + bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data) const + { + if (!has_data ()) + return false; + + int x_offset = 0, y_offset = 0; + unsigned int strike_ppem = 0; + hb_blob_t *blob = reference_png (font, glyph, &x_offset, &y_offset, &strike_ppem); + hb_glyph_extents_t extents; + hb_glyph_extents_t pixel_extents; + + if (blob == hb_blob_get_empty ()) + return false; + + if (!hb_font_get_glyph_extents (font, glyph, &extents)) + return false; + + if (unlikely (!get_extents (font, glyph, &pixel_extents, false))) + return false; + + bool ret = funcs->image (data, + blob, + pixel_extents.width, -pixel_extents.height, + HB_PAINT_IMAGE_FORMAT_PNG, + font->slant_xy, + &extents); + + hb_blob_destroy (blob); + return ret; + } + private: const SBIXStrike &choose_strike (hb_font_t *font) const @@ -285,7 +315,8 @@ struct sbix bool get_png_extents (hb_font_t *font, hb_codepoint_t glyph, - hb_glyph_extents_t *extents) const + hb_glyph_extents_t *extents, + bool scale = true) const { /* Following code is safe to call even without data. * But faster to short-circuit. */ @@ -310,22 +341,18 @@ struct sbix extents->height = -1 * png.IHDR.height; /* Convert to font units. */ - if (strike_ppem) + if (strike_ppem && scale) { float scale = font->face->get_upem () / (float) strike_ppem; - extents->x_bearing = font->em_scalef_x (extents->x_bearing * scale); - extents->y_bearing = font->em_scalef_y (extents->y_bearing * scale); - extents->width = font->em_scalef_x (extents->width * scale); - extents->height = font->em_scalef_y (extents->height * scale); - } - else - { - extents->x_bearing = font->em_scale_x (extents->x_bearing); - extents->y_bearing = font->em_scale_y (extents->y_bearing); - extents->width = font->em_scale_x (extents->width); - extents->height = font->em_scale_y (extents->height); + extents->x_bearing = roundf (extents->x_bearing * scale); + extents->y_bearing = roundf (extents->y_bearing * scale); + extents->width = roundf (extents->width * scale); + extents->height = roundf (extents->height * scale); } + if (scale) + font->scale_glyph_extents (extents); + hb_blob_destroy (blob); return strike_ppem; @@ -341,6 +368,7 @@ struct sbix { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && + hb_barrier () && version >= 1 && strikes.sanitize (c, this))); } @@ -359,7 +387,6 @@ struct sbix TRACE_SERIALIZE (this); auto *out = c->serializer->start_embed> (); - if (unlikely (!out)) return_trace (false); if (unlikely (!c->serializer->extend_min (out))) return_trace (false); hb_vector_t*> new_strikes; @@ -394,8 +421,6 @@ struct sbix { TRACE_SUBSET (this); - sbix *sbix_prime = c->serializer->start_embed (); - if (unlikely (!sbix_prime)) return_trace (false); if (unlikely (!c->serializer->embed (this->version))) return_trace (false); if (unlikely (!c->serializer->embed (this->flags))) return_trace (false); @@ -420,4 +445,4 @@ struct sbix_accelerator_t : sbix::accelerator_t { } /* namespace OT */ -#endif /* HB_OT_COLOR_SBIX_TABLE_HH */ +#endif /* OT_COLOR_SBIX_SBIX_HH */ diff --git a/libs/harfbuzz/src/hb-ot-color-svg-table.hh b/libs/harfbuzz/src/OT/Color/svg/svg.hh similarity index 83% rename from libs/harfbuzz/src/hb-ot-color-svg-table.hh rename to libs/harfbuzz/src/OT/Color/svg/svg.hh index fc649f100..2e1f93510 100644 --- a/libs/harfbuzz/src/hb-ot-color-svg-table.hh +++ b/libs/harfbuzz/src/OT/Color/svg/svg.hh @@ -22,10 +22,12 @@ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ -#ifndef HB_OT_COLOR_SVG_TABLE_HH -#define HB_OT_COLOR_SVG_TABLE_HH +#ifndef OT_COLOR_SVG_SVG_HH +#define OT_COLOR_SVG_SVG_HH -#include "hb-open-type.hh" +#include "../../../hb-open-type.hh" +#include "../../../hb-blob.hh" +#include "../../../hb-paint.hh" /* * SVG -- SVG (Scalable Vector Graphics) @@ -54,6 +56,7 @@ struct SVGDocumentIndexEntry { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && + hb_barrier () && svgDoc.sanitize (c, base, svgDocLength)); } @@ -91,8 +94,31 @@ struct SVG bool has_data () const { return table->has_data (); } + bool paint_glyph (hb_font_t *font HB_UNUSED, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data) const + { + if (!has_data ()) + return false; + + hb_blob_t *blob = reference_blob_for_glyph (glyph); + + if (blob == hb_blob_get_empty ()) + return false; + + funcs->image (data, + blob, + 0, 0, + HB_PAINT_IMAGE_FORMAT_SVG, + font->slant_xy, + nullptr); + + hb_blob_destroy (blob); + return true; + } + private: hb_blob_ptr_t table; + public: + DEFINE_SIZE_STATIC (sizeof (hb_blob_ptr_t)); }; const SVGDocumentIndexEntry &get_glyph_entry (hb_codepoint_t glyph_id) const @@ -123,4 +149,4 @@ struct SVG_accelerator_t : SVG::accelerator_t { } /* namespace OT */ -#endif /* HB_OT_COLOR_SVG_TABLE_HH */ +#endif /* OT_COLOR_SVG_SVG_HH */ diff --git a/libs/harfbuzz/src/OT/Layout/Common/Coverage.hh b/libs/harfbuzz/src/OT/Layout/Common/Coverage.hh index eef89a287..344e87afb 100644 --- a/libs/harfbuzz/src/OT/Layout/Common/Coverage.hh +++ b/libs/harfbuzz/src/OT/Layout/Common/Coverage.hh @@ -49,7 +49,7 @@ struct Coverage HBUINT16 format; /* Format identifier */ CoverageFormat1_3 format1; CoverageFormat2_4 format2; -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K CoverageFormat1_3format3; CoverageFormat2_4format4; #endif @@ -57,15 +57,19 @@ struct Coverage public: DEFINE_SIZE_UNION (2, format); +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return_trace (false); + hb_barrier (); switch (u.format) { case 1: return_trace (u.format1.sanitize (c)); case 2: return_trace (u.format2.sanitize (c)); -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K case 3: return_trace (u.format3.sanitize (c)); case 4: return_trace (u.format4.sanitize (c)); #endif @@ -74,10 +78,8 @@ struct Coverage } /* Has interface. */ - static constexpr unsigned SENTINEL = NOT_COVERED; - typedef unsigned int value_t; - value_t operator [] (hb_codepoint_t k) const { return get (k); } - bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; } + unsigned operator [] (hb_codepoint_t k) const { return get (k); } + bool has (hb_codepoint_t k) const { return (*this)[k] != NOT_COVERED; } /* Predicate. */ bool operator () (hb_codepoint_t k) const { return has (k); } @@ -87,7 +89,7 @@ struct Coverage switch (u.format) { case 1: return u.format1.get_coverage (glyph_id); case 2: return u.format2.get_coverage (glyph_id); -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K case 3: return u.format3.get_coverage (glyph_id); case 4: return u.format4.get_coverage (glyph_id); #endif @@ -100,7 +102,7 @@ struct Coverage switch (u.format) { case 1: return u.format1.get_population (); case 2: return u.format2.get_population (); -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K case 3: return u.format3.get_population (); case 4: return u.format4.get_population (); #endif @@ -115,28 +117,39 @@ struct Coverage TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (this))) return_trace (false); - unsigned count = 0; + unsigned count = hb_len (glyphs); unsigned num_ranges = 0; hb_codepoint_t last = (hb_codepoint_t) -2; + hb_codepoint_t max = 0; + bool unsorted = false; for (auto g: glyphs) { + if (last != (hb_codepoint_t) -2 && g < last) + unsorted = true; if (last + 1 != g) - num_ranges++; + num_ranges++; last = g; - count++; + if (g > max) max = g; } - u.format = count <= num_ranges * 3 ? 1 : 2; + u.format = !unsorted && count <= num_ranges * 3 ? 1 : 2; -#ifndef HB_NO_BORING_EXPANSION - if (count && last > 0xFFFFu) +#ifndef HB_NO_BEYOND_64K + if (max > 0xFFFFu) u.format += 2; + if (unlikely (max > 0xFFFFFFu)) +#else + if (unlikely (max > 0xFFFFu)) #endif + { + c->check_success (false, HB_SERIALIZE_ERROR_INT_OVERFLOW); + return_trace (false); + } switch (u.format) { case 1: return_trace (u.format1.serialize (c, glyphs)); case 2: return_trace (u.format2.serialize (c, glyphs)); -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K case 3: return_trace (u.format3.serialize (c, glyphs)); case 4: return_trace (u.format4.serialize (c, glyphs)); #endif @@ -149,8 +162,9 @@ struct Coverage TRACE_SUBSET (this); auto it = + iter () - | hb_filter (c->plan->glyph_map_gsub) + | hb_take (c->plan->source->get_num_glyphs ()) | hb_map_retains_sorting (c->plan->glyph_map_gsub) + | hb_filter ([] (hb_codepoint_t glyph) { return glyph != HB_MAP_VALUE_INVALID; }) ; // Cache the iterator result as it will be iterated multiple times @@ -166,7 +180,7 @@ struct Coverage { case 1: return u.format1.intersects (glyphs); case 2: return u.format2.intersects (glyphs); -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K case 3: return u.format3.intersects (glyphs); case 4: return u.format4.intersects (glyphs); #endif @@ -179,7 +193,7 @@ struct Coverage { case 1: return u.format1.intersects_coverage (glyphs, index); case 2: return u.format2.intersects_coverage (glyphs, index); -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K case 3: return u.format3.intersects_coverage (glyphs, index); case 4: return u.format4.intersects_coverage (glyphs, index); #endif @@ -196,7 +210,7 @@ struct Coverage { case 1: return u.format1.collect_coverage (glyphs); case 2: return u.format2.collect_coverage (glyphs); -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K case 3: return u.format3.collect_coverage (glyphs); case 4: return u.format4.collect_coverage (glyphs); #endif @@ -212,7 +226,7 @@ struct Coverage { case 1: return u.format1.intersect_set (glyphs, intersect_glyphs); case 2: return u.format2.intersect_set (glyphs, intersect_glyphs); -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K case 3: return u.format3.intersect_set (glyphs, intersect_glyphs); case 4: return u.format4.intersect_set (glyphs, intersect_glyphs); #endif @@ -225,13 +239,13 @@ struct Coverage static constexpr bool is_sorted_iterator = true; iter_t (const Coverage &c_ = Null (Coverage)) { - memset (this, 0, sizeof (*this)); + hb_memset (this, 0, sizeof (*this)); format = c_.u.format; switch (format) { case 1: u.format1.init (c_.u.format1); return; case 2: u.format2.init (c_.u.format2); return; -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K case 3: u.format3.init (c_.u.format3); return; case 4: u.format4.init (c_.u.format4); return; #endif @@ -244,7 +258,7 @@ struct Coverage { case 1: return u.format1.__more__ (); case 2: return u.format2.__more__ (); -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K case 3: return u.format3.__more__ (); case 4: return u.format4.__more__ (); #endif @@ -257,7 +271,7 @@ struct Coverage { case 1: u.format1.__next__ (); break; case 2: u.format2.__next__ (); break; -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K case 3: u.format3.__next__ (); break; case 4: u.format4.__next__ (); break; #endif @@ -273,7 +287,7 @@ struct Coverage { case 1: return u.format1.get_glyph (); case 2: return u.format2.get_glyph (); -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K case 3: return u.format3.get_glyph (); case 4: return u.format4.get_glyph (); #endif @@ -287,7 +301,7 @@ struct Coverage { case 1: return u.format1 != o.u.format1; case 2: return u.format2 != o.u.format2; -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K case 3: return u.format3 != o.u.format3; case 4: return u.format4 != o.u.format4; #endif @@ -302,7 +316,7 @@ struct Coverage { case 1: it.u.format1 = u.format1.__end__ (); break; case 2: it.u.format2 = u.format2.__end__ (); break; -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K case 3: it.u.format3 = u.format3.__end__ (); break; case 4: it.u.format4 = u.format4.__end__ (); break; #endif @@ -314,7 +328,7 @@ struct Coverage private: unsigned int format; union { -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K CoverageFormat2_4::iter_t format4; /* Put this one first since it's larger; helps shut up compiler. */ CoverageFormat1_3::iter_t format3; #endif diff --git a/libs/harfbuzz/src/OT/Layout/Common/CoverageFormat1.hh b/libs/harfbuzz/src/OT/Layout/Common/CoverageFormat1.hh index 82fd48dc5..3f598d40e 100644 --- a/libs/harfbuzz/src/OT/Layout/Common/CoverageFormat1.hh +++ b/libs/harfbuzz/src/OT/Layout/Common/CoverageFormat1.hh @@ -77,7 +77,14 @@ struct CoverageFormat1_3 bool intersects (const hb_set_t *glyphs) const { - /* TODO Speed up, using hb_set_next() and bsearch()? */ + if (glyphArray.len > glyphs->get_population () * hb_bit_storage ((unsigned) glyphArray.len) / 2) + { + for (auto g : *glyphs) + if (get_coverage (g) != NOT_COVERED) + return true; + return false; + } + for (const auto& g : glyphArray.as_array ()) if (glyphs->has (g)) return true; diff --git a/libs/harfbuzz/src/OT/Layout/Common/CoverageFormat2.hh b/libs/harfbuzz/src/OT/Layout/Common/CoverageFormat2.hh index 974d09463..9c8754235 100644 --- a/libs/harfbuzz/src/OT/Layout/Common/CoverageFormat2.hh +++ b/libs/harfbuzz/src/OT/Layout/Common/CoverageFormat2.hh @@ -80,8 +80,6 @@ struct CoverageFormat2_4 TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (this))) return_trace (false); - /* TODO(iter) Write more efficiently? */ - unsigned num_ranges = 0; hb_codepoint_t last = (hb_codepoint_t) -2; for (auto g: glyphs) @@ -97,44 +95,47 @@ struct CoverageFormat2_4 unsigned count = 0; unsigned range = (unsigned) -1; last = (hb_codepoint_t) -2; + unsigned unsorted = false; for (auto g: glyphs) { if (last + 1 != g) { + if (unlikely (last != (hb_codepoint_t) -2 && last + 1 > g)) + unsorted = true; + range++; - rangeRecord[range].first = g; - rangeRecord[range].value = count; + rangeRecord.arrayZ[range].first = g; + rangeRecord.arrayZ[range].value = count; } - rangeRecord[range].last = g; + rangeRecord.arrayZ[range].last = g; last = g; count++; } + if (unlikely (unsorted)) + rangeRecord.as_array ().qsort (RangeRecord::cmp_range); + return_trace (true); } bool intersects (const hb_set_t *glyphs) const { + if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2) + { + for (auto g : *glyphs) + if (get_coverage (g) != NOT_COVERED) + return true; + return false; + } + return hb_any (+ hb_iter (rangeRecord) | hb_map ([glyphs] (const RangeRecord &range) { return range.intersects (*glyphs); })); } bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { - auto cmp = [] (const void *pk, const void *pr) -> int - { - unsigned index = * (const unsigned *) pk; - const RangeRecord &range = * (const RangeRecord *) pr; - if (index < range.value) return -1; - if (index > (unsigned int) range.value + (range.last - range.first)) return +1; - return 0; - }; - - auto arr = rangeRecord.as_array (); - unsigned idx; - if (hb_bsearch_impl (&idx, index, - arr.arrayZ, arr.length, sizeof (arr[0]), - (int (*)(const void *_key, const void *_item)) cmp)) - return arr.arrayZ[idx].intersects (*glyphs); + auto *range = rangeRecord.as_array ().bsearch (index); + if (range) + return range->intersects (*glyphs); return false; } @@ -142,9 +143,14 @@ struct CoverageFormat2_4 hb_requires (hb_is_sink_of (IterableOut, hb_codepoint_t))> void intersect_set (const hb_set_t &glyphs, IterableOut&& intersect_glyphs) const { + /* Break out of loop for overlapping, broken, tables, + * to avoid fuzzer timouts. */ + hb_codepoint_t last = 0; for (const auto& range : rangeRecord) { - hb_codepoint_t last = range.last; + if (unlikely (range.first < last)) + break; + last = range.last; for (hb_codepoint_t g = range.first - 1; glyphs.next (&g) && g <= last;) intersect_glyphs << g; @@ -186,8 +192,8 @@ struct CoverageFormat2_4 if (__more__ ()) { unsigned int old = coverage; - j = c->rangeRecord[i].first; - coverage = c->rangeRecord[i].value; + j = c->rangeRecord.arrayZ[i].first; + coverage = c->rangeRecord.arrayZ[i].value; if (unlikely (coverage != old + 1)) { /* Broken table. Skip. Important to avoid DoS. diff --git a/libs/harfbuzz/src/OT/Layout/Common/RangeRecord.hh b/libs/harfbuzz/src/OT/Layout/Common/RangeRecord.hh index a62629fad..85aacace9 100644 --- a/libs/harfbuzz/src/OT/Layout/Common/RangeRecord.hh +++ b/libs/harfbuzz/src/OT/Layout/Common/RangeRecord.hh @@ -51,6 +51,18 @@ struct RangeRecord int cmp (hb_codepoint_t g) const { return g < first ? -1 : g <= last ? 0 : +1; } + HB_INTERNAL static int cmp_range (const void *pa, const void *pb) { + const RangeRecord *a = (const RangeRecord *) pa; + const RangeRecord *b = (const RangeRecord *) pb; + if (a->first < b->first) return -1; + if (a->first > b->first) return +1; + if (a->last < b->last) return -1; + if (a->last > b->last) return +1; + if (a->value < b->value) return -1; + if (a->value > b->value) return +1; + return 0; + } + unsigned get_population () const { if (unlikely (last < first)) return 0; diff --git a/libs/harfbuzz/src/OT/Layout/GDEF/GDEF.hh b/libs/harfbuzz/src/OT/Layout/GDEF/GDEF.hh new file mode 100644 index 000000000..16b232a2a --- /dev/null +++ b/libs/harfbuzz/src/OT/Layout/GDEF/GDEF.hh @@ -0,0 +1,1044 @@ +/* + * Copyright © 2007,2008,2009 Red Hat, Inc. + * Copyright © 2010,2011,2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef OT_LAYOUT_GDEF_GDEF_HH +#define OT_LAYOUT_GDEF_GDEF_HH + +#include "../../../hb-ot-var-common.hh" + +#include "../../../hb-font.hh" +#include "../../../hb-cache.hh" + + +namespace OT { + + +/* + * Attachment List Table + */ + +/* Array of contour point indices--in increasing numerical order */ +struct AttachPoint : Array16Of +{ + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + return_trace (out->serialize (c->serializer, + iter ())); + } +}; + +struct AttachList +{ + unsigned int get_attach_points (hb_codepoint_t glyph_id, + unsigned int start_offset, + unsigned int *point_count /* IN/OUT */, + unsigned int *point_array /* OUT */) const + { + unsigned int index = (this+coverage).get_coverage (glyph_id); + if (index == NOT_COVERED) + { + if (point_count) + *point_count = 0; + return 0; + } + + const AttachPoint &points = this+attachPoint[index]; + + if (point_count) + { + + points.as_array ().sub_array (start_offset, point_count) + | hb_sink (hb_array (point_array, *point_count)) + ; + } + + return points.len; + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + + hb_sorted_vector_t new_coverage; + + hb_zip (this+coverage, attachPoint) + | hb_filter (glyphset, hb_first) + | hb_filter (subset_offset_array (c, out->attachPoint, this), hb_second) + | hb_map (hb_first) + | hb_map (glyph_map) + | hb_sink (new_coverage) + ; + out->coverage.serialize_serialize (c->serializer, new_coverage.iter ()); + return_trace (bool (new_coverage)); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (coverage.sanitize (c, this) && attachPoint.sanitize (c, this)); + } + + protected: + Offset16To + coverage; /* Offset to Coverage table -- from + * beginning of AttachList table */ + Array16OfOffset16To + attachPoint; /* Array of AttachPoint tables + * in Coverage Index order */ + public: + DEFINE_SIZE_ARRAY (4, attachPoint); +}; + +/* + * Ligature Caret Table + */ + +struct CaretValueFormat1 +{ + friend struct CaretValue; + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + return_trace (true); + } + + private: + hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction) const + { + return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + protected: + HBUINT16 caretValueFormat; /* Format identifier--format = 1 */ + FWORD coordinate; /* X or Y value, in design units */ + public: + DEFINE_SIZE_STATIC (4); +}; + +struct CaretValueFormat2 +{ + friend struct CaretValue; + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + return_trace (true); + } + + private: + hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const + { + hb_position_t x, y; + font->get_glyph_contour_point_for_origin (glyph_id, caretValuePoint, direction, &x, &y); + return HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y; + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + protected: + HBUINT16 caretValueFormat; /* Format identifier--format = 2 */ + HBUINT16 caretValuePoint; /* Contour point index on glyph */ + public: + DEFINE_SIZE_STATIC (4); +}; + +struct CaretValueFormat3 +{ + friend struct CaretValue; + + hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, + const ItemVariationStore &var_store) const + { + return HB_DIRECTION_IS_HORIZONTAL (direction) ? + font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) : + font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font, var_store); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (!c->serializer->embed (caretValueFormat)) return_trace (false); + if (!c->serializer->embed (coordinate)) return_trace (false); + + unsigned varidx = (this+deviceTable).get_variation_index (); + hb_pair_t *new_varidx_delta; + if (!c->plan->layout_variation_idx_delta_map.has (varidx, &new_varidx_delta)) + return_trace (false); + + 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); + + return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable, this, c->serializer->to_bias (out), + hb_serialize_context_t::Head, &c->plan->layout_variation_idx_delta_map)); + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { (this+deviceTable).collect_variation_indices (c); } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && deviceTable.sanitize (c, this)); + } + + protected: + HBUINT16 caretValueFormat; /* Format identifier--format = 3 */ + FWORD coordinate; /* X or Y value, in design units */ + Offset16To + deviceTable; /* Offset to Device table for X or Y + * value--from beginning of CaretValue + * table */ + public: + DEFINE_SIZE_STATIC (6); +}; + +struct CaretValue +{ + hb_position_t get_caret_value (hb_font_t *font, + hb_direction_t direction, + hb_codepoint_t glyph_id, + const ItemVariationStore &var_store) const + { + switch (u.format) { + case 1: return u.format1.get_caret_value (font, direction); + case 2: return u.format2.get_caret_value (font, direction, glyph_id); + case 3: return u.format3.get_caret_value (font, direction, var_store); + default:return 0; + } + } + + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const + { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); + TRACE_DISPATCH (this, u.format); + switch (u.format) { + case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); + case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); + case 3: return_trace (c->dispatch (u.format3, std::forward (ds)...)); + default:return_trace (c->default_return_value ()); + } + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + switch (u.format) { + case 1: + case 2: + return; + case 3: + u.format3.collect_variation_indices (c); + return; + default: return; + } + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (!u.format.sanitize (c)) return_trace (false); + hb_barrier (); + switch (u.format) { + case 1: return_trace (u.format1.sanitize (c)); + case 2: return_trace (u.format2.sanitize (c)); + case 3: return_trace (u.format3.sanitize (c)); + default:return_trace (true); + } + } + + protected: + union { + HBUINT16 format; /* Format identifier */ + CaretValueFormat1 format1; + CaretValueFormat2 format2; + CaretValueFormat3 format3; + } u; + public: + DEFINE_SIZE_UNION (2, format); +}; + +struct LigGlyph +{ + unsigned get_lig_carets (hb_font_t *font, + hb_direction_t direction, + hb_codepoint_t glyph_id, + const ItemVariationStore &var_store, + unsigned start_offset, + unsigned *caret_count /* IN/OUT */, + hb_position_t *caret_array /* OUT */) const + { + if (caret_count) + { + + carets.as_array ().sub_array (start_offset, caret_count) + | hb_map (hb_add (this)) + | hb_map ([&] (const CaretValue &value) { return value.get_caret_value (font, direction, glyph_id, var_store); }) + | hb_sink (hb_array (caret_array, *caret_count)) + ; + } + + return carets.len; + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + + + hb_iter (carets) + | hb_apply (subset_offset_array (c, out->carets, this)) + ; + + return_trace (bool (out->carets)); + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + for (const Offset16To& offset : carets.iter ()) + (this+offset).collect_variation_indices (c); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (carets.sanitize (c, this)); + } + + protected: + Array16OfOffset16To + carets; /* Offset array of CaretValue tables + * --from beginning of LigGlyph table + * --in increasing coordinate order */ + public: + DEFINE_SIZE_ARRAY (2, carets); +}; + +struct LigCaretList +{ + unsigned int get_lig_carets (hb_font_t *font, + hb_direction_t direction, + hb_codepoint_t glyph_id, + const ItemVariationStore &var_store, + unsigned int start_offset, + unsigned int *caret_count /* IN/OUT */, + hb_position_t *caret_array /* OUT */) const + { + unsigned int index = (this+coverage).get_coverage (glyph_id); + if (index == NOT_COVERED) + { + if (caret_count) + *caret_count = 0; + return 0; + } + const LigGlyph &lig_glyph = this+ligGlyph[index]; + return lig_glyph.get_lig_carets (font, direction, glyph_id, var_store, start_offset, caret_count, caret_array); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + + hb_sorted_vector_t new_coverage; + + hb_zip (this+coverage, ligGlyph) + | hb_filter (glyphset, hb_first) + | hb_filter (subset_offset_array (c, out->ligGlyph, this), hb_second) + | hb_map (hb_first) + | hb_map (glyph_map) + | hb_sink (new_coverage) + ; + out->coverage.serialize_serialize (c->serializer, new_coverage.iter ()); + return_trace (bool (new_coverage)); + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + + hb_zip (this+coverage, ligGlyph) + | hb_filter (c->glyph_set, hb_first) + | hb_map (hb_second) + | hb_map (hb_add (this)) + | hb_apply ([c] (const LigGlyph& _) { _.collect_variation_indices (c); }) + ; + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this)); + } + + protected: + Offset16To + coverage; /* Offset to Coverage table--from + * beginning of LigCaretList table */ + Array16OfOffset16To + ligGlyph; /* Array of LigGlyph tables + * in Coverage Index order */ + public: + DEFINE_SIZE_ARRAY (4, ligGlyph); +}; + + +struct MarkGlyphSetsFormat1 +{ + bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const + { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; } + + void collect_used_mark_sets (const hb_set_t& glyph_set, + hb_set_t& used_mark_sets /* OUT */) const + { + unsigned i = 0; + for (const auto &offset : coverage) + { + const auto &cov = this+offset; + if (cov.intersects (&glyph_set)) + used_mark_sets.add (i); + + i++; + } + } + + template + void collect_coverage (hb_vector_t &sets) const + { + for (const auto &offset : coverage) + { + const auto &cov = this+offset; + cov.collect_coverage (sets.push ()); + } + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + out->format = format; + + bool ret = true; + for (const Offset32To& offset : coverage.iter ()) + { + auto snap = c->serializer->snapshot (); + auto *o = out->coverage.serialize_append (c->serializer); + if (unlikely (!o)) + { + ret = false; + break; + } + + //skip empty coverage + c->serializer->push (); + bool res = false; + if (offset) res = c->dispatch (this+offset); + if (!res) + { + c->serializer->pop_discard (); + c->serializer->revert (snap); + (out->coverage.len)--; + continue; + } + c->serializer->add_link (*o, c->serializer->pop_pack ()); + } + + return_trace (ret && out->coverage.len); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (coverage.sanitize (c, this)); + } + + protected: + HBUINT16 format; /* Format identifier--format = 1 */ + Array16Of> + coverage; /* Array of long offsets to mark set + * coverage tables */ + public: + DEFINE_SIZE_ARRAY (4, coverage); +}; + +struct MarkGlyphSets +{ + bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const + { + switch (u.format) { + case 1: return u.format1.covers (set_index, glyph_id); + default:return false; + } + } + + template + void collect_coverage (hb_vector_t &sets) const + { + switch (u.format) { + case 1: u.format1.collect_coverage (sets); return; + default:return; + } + } + + void collect_used_mark_sets (const hb_set_t& glyph_set, + hb_set_t& used_mark_sets /* OUT */) const + { + switch (u.format) { + case 1: u.format1.collect_used_mark_sets (glyph_set, used_mark_sets); return; + default:return; + } + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + switch (u.format) { + case 1: return_trace (u.format1.subset (c)); + default:return_trace (false); + } + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (!u.format.sanitize (c)) return_trace (false); + hb_barrier (); + switch (u.format) { + case 1: return_trace (u.format1.sanitize (c)); + default:return_trace (true); + } + } + + protected: + union { + HBUINT16 format; /* Format identifier */ + MarkGlyphSetsFormat1 format1; + } u; + public: + DEFINE_SIZE_UNION (2, format); +}; + + +/* + * GDEF -- Glyph Definition + * https://docs.microsoft.com/en-us/typography/opentype/spec/gdef + */ + + +template +struct GDEFVersion1_2 +{ + friend struct GDEF; + + protected: + FixedVersion<>version; /* Version of the GDEF table--currently + * 0x00010003u */ + typename Types::template OffsetTo + glyphClassDef; /* Offset to class definition table + * for glyph type--from beginning of + * GDEF header (may be Null) */ + typename Types::template OffsetTo + attachList; /* Offset to list of glyphs with + * attachment points--from beginning + * of GDEF header (may be Null) */ + typename Types::template OffsetTo + ligCaretList; /* Offset to list of positioning points + * for ligature carets--from beginning + * of GDEF header (may be Null) */ + typename Types::template OffsetTo + markAttachClassDef; /* Offset to class definition table for + * mark attachment type--from beginning + * of GDEF header (may be Null) */ + typename Types::template OffsetTo + markGlyphSetsDef; /* Offset to the table of mark set + * definitions--from beginning of GDEF + * header (may be NULL). Introduced + * in version 0x00010002. */ + Offset32To + varStore; /* Offset to the table of Item Variation + * Store--from beginning of GDEF + * header (may be NULL). Introduced + * in version 0x00010003. */ + public: + DEFINE_SIZE_MIN (4 + 4 * Types::size); + + unsigned int get_size () const + { + return min_size + + (version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) + + (version.to_int () >= 0x00010003u ? varStore.static_size : 0); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (version.sanitize (c) && + glyphClassDef.sanitize (c, this) && + attachList.sanitize (c, this) && + ligCaretList.sanitize (c, this) && + markAttachClassDef.sanitize (c, this) && + hb_barrier () && + ((version.to_int () < 0x00010002u && hb_barrier ()) || markGlyphSetsDef.sanitize (c, this)) && + ((version.to_int () < 0x00010003u && hb_barrier ()) || varStore.sanitize (c, this))); + } + + static void remap_varidx_after_instantiation (const hb_map_t& varidx_map, + hb_hashmap_t>& layout_variation_idx_delta_map /* IN/OUT */) + { + /* varidx_map is empty which means varstore is empty after instantiation, + * no variations, map all varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX. + * varidx_map doesn't have original varidx, indicating delta row is all + * zeros, map varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX */ + for (auto _ : layout_variation_idx_delta_map.iter_ref ()) + { + /* old_varidx->(varidx, delta) mapping generated for subsetting, then this + * varidx is used as key of varidx_map during instantiation */ + uint32_t varidx = _.second.first; + uint32_t *new_varidx; + if (varidx_map.has (varidx, &new_varidx)) + _.second.first = *new_varidx; + else + _.second.first = HB_OT_LAYOUT_NO_VARIATIONS_INDEX; + } + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + + // Push var store first (if it's needed) so that it's last in the + // serialization order. Some font consumers assume that varstore runs to + // the end of the GDEF table. + // See: https://github.com/harfbuzz/harfbuzz/issues/4636 + auto snapshot_version0 = c->serializer->snapshot (); + if (unlikely (version.to_int () >= 0x00010002u && hb_barrier () && !c->serializer->embed (markGlyphSetsDef))) + return_trace (false); + + bool subset_varstore = false; + unsigned varstore_index = (unsigned) -1; + auto snapshot_version2 = c->serializer->snapshot (); + if (version.to_int () >= 0x00010003u && hb_barrier ()) + { + if (unlikely (!c->serializer->embed (varStore))) return_trace (false); + if (c->plan->all_axes_pinned) + out->varStore = 0; + else if (c->plan->normalized_coords) + { + if (varStore) + { + item_variations_t item_vars; + if (item_vars.instantiate (this+varStore, c->plan, true, true, + c->plan->gdef_varstore_inner_maps.as_array ())) { + subset_varstore = out->varStore.serialize_serialize (c->serializer, + item_vars.has_long_word (), + c->plan->axis_tags, + item_vars.get_region_list (), + item_vars.get_vardata_encodings ()); + varstore_index = c->serializer->last_added_child_index(); + } + remap_varidx_after_instantiation (item_vars.get_varidx_map (), + c->plan->layout_variation_idx_delta_map); + } + } + else + { + subset_varstore = out->varStore.serialize_subset (c, varStore, this, c->plan->gdef_varstore_inner_maps.as_array ()); + varstore_index = c->serializer->last_added_child_index(); + } + } + + out->version.major = version.major; + out->version.minor = version.minor; + + if (!subset_varstore && version.to_int () >= 0x00010002u) { + c->serializer->revert (snapshot_version2); + } + + bool subset_markglyphsetsdef = false; + if (version.to_int () >= 0x00010002u && hb_barrier ()) + { + subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this); + } + + if (subset_varstore) + { + out->version.minor = 3; + c->plan->has_gdef_varstore = true; + } else if (subset_markglyphsetsdef) { + out->version.minor = 2; + } else { + out->version.minor = 0; + c->serializer->revert (snapshot_version0); + } + + bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true); + bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this); + bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true); + bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this); + + if (subset_varstore && varstore_index != (unsigned) -1) { + c->serializer->repack_last(varstore_index); + } + + return_trace (subset_glyphclassdef || subset_attachlist || + subset_ligcaretlist || subset_markattachclassdef || + (out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) || + (out->version.to_int () >= 0x00010003u && subset_varstore)); + } +}; + +struct GDEF +{ + static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF; + + enum GlyphClasses { + UnclassifiedGlyph = 0, + BaseGlyph = 1, + LigatureGlyph = 2, + MarkGlyph = 3, + ComponentGlyph = 4 + }; + + unsigned int get_size () const + { + switch (u.version.major) { + case 1: return u.version1.get_size (); +#ifndef HB_NO_BEYOND_64K + case 2: return u.version2.get_size (); +#endif + default: return u.version.static_size; + } + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (unlikely (!u.version.sanitize (c))) return_trace (false); + hb_barrier (); + switch (u.version.major) { + case 1: return_trace (u.version1.sanitize (c)); +#ifndef HB_NO_BEYOND_64K + case 2: return_trace (u.version2.sanitize (c)); +#endif + default: return_trace (true); + } + } + + bool subset (hb_subset_context_t *c) const + { + switch (u.version.major) { + case 1: return u.version1.subset (c); +#ifndef HB_NO_BEYOND_64K + case 2: return u.version2.subset (c); +#endif + default: return false; + } + } + + bool has_glyph_classes () const + { + switch (u.version.major) { + case 1: return u.version1.glyphClassDef != 0; +#ifndef HB_NO_BEYOND_64K + case 2: return u.version2.glyphClassDef != 0; +#endif + default: return false; + } + } + const ClassDef &get_glyph_class_def () const + { + switch (u.version.major) { + case 1: return this+u.version1.glyphClassDef; +#ifndef HB_NO_BEYOND_64K + case 2: return this+u.version2.glyphClassDef; +#endif + default: return Null(ClassDef); + } + } + bool has_attach_list () const + { + switch (u.version.major) { + case 1: return u.version1.attachList != 0; +#ifndef HB_NO_BEYOND_64K + case 2: return u.version2.attachList != 0; +#endif + default: return false; + } + } + const AttachList &get_attach_list () const + { + switch (u.version.major) { + case 1: return this+u.version1.attachList; +#ifndef HB_NO_BEYOND_64K + case 2: return this+u.version2.attachList; +#endif + default: return Null(AttachList); + } + } + bool has_lig_carets () const + { + switch (u.version.major) { + case 1: return u.version1.ligCaretList != 0; +#ifndef HB_NO_BEYOND_64K + case 2: return u.version2.ligCaretList != 0; +#endif + default: return false; + } + } + const LigCaretList &get_lig_caret_list () const + { + switch (u.version.major) { + case 1: return this+u.version1.ligCaretList; +#ifndef HB_NO_BEYOND_64K + case 2: return this+u.version2.ligCaretList; +#endif + default: return Null(LigCaretList); + } + } + bool has_mark_attachment_types () const + { + switch (u.version.major) { + case 1: return u.version1.markAttachClassDef != 0; +#ifndef HB_NO_BEYOND_64K + case 2: return u.version2.markAttachClassDef != 0; +#endif + default: return false; + } + } + const ClassDef &get_mark_attach_class_def () const + { + switch (u.version.major) { + case 1: return this+u.version1.markAttachClassDef; +#ifndef HB_NO_BEYOND_64K + case 2: return this+u.version2.markAttachClassDef; +#endif + default: return Null(ClassDef); + } + } + bool has_mark_glyph_sets () const + { + switch (u.version.major) { + case 1: return u.version.to_int () >= 0x00010002u && hb_barrier () && u.version1.markGlyphSetsDef != 0; +#ifndef HB_NO_BEYOND_64K + case 2: return u.version2.markGlyphSetsDef != 0; +#endif + default: return false; + } + } + const MarkGlyphSets &get_mark_glyph_sets () const + { + switch (u.version.major) { + case 1: return u.version.to_int () >= 0x00010002u && hb_barrier () ? this+u.version1.markGlyphSetsDef : Null(MarkGlyphSets); +#ifndef HB_NO_BEYOND_64K + case 2: return this+u.version2.markGlyphSetsDef; +#endif + default: return Null(MarkGlyphSets); + } + } + bool has_var_store () const + { + switch (u.version.major) { + case 1: return u.version.to_int () >= 0x00010003u && hb_barrier () && u.version1.varStore != 0; +#ifndef HB_NO_BEYOND_64K + case 2: return u.version2.varStore != 0; +#endif + default: return false; + } + } + const ItemVariationStore &get_var_store () const + { + switch (u.version.major) { + case 1: return u.version.to_int () >= 0x00010003u && hb_barrier () ? this+u.version1.varStore : Null(ItemVariationStore); +#ifndef HB_NO_BEYOND_64K + case 2: return this+u.version2.varStore; +#endif + default: return Null(ItemVariationStore); + } + } + + + bool has_data () const { return u.version.to_int (); } + unsigned int get_glyph_class (hb_codepoint_t glyph) const + { return get_glyph_class_def ().get_class (glyph); } + void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const + { get_glyph_class_def ().collect_class (glyphs, klass); } + + unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const + { return get_mark_attach_class_def ().get_class (glyph); } + + unsigned int get_attach_points (hb_codepoint_t glyph_id, + unsigned int start_offset, + unsigned int *point_count /* IN/OUT */, + unsigned int *point_array /* OUT */) const + { return get_attach_list ().get_attach_points (glyph_id, start_offset, point_count, point_array); } + + unsigned int get_lig_carets (hb_font_t *font, + hb_direction_t direction, + hb_codepoint_t glyph_id, + unsigned int start_offset, + unsigned int *caret_count /* IN/OUT */, + hb_position_t *caret_array /* OUT */) const + { return get_lig_caret_list ().get_lig_carets (font, + direction, glyph_id, get_var_store(), + start_offset, caret_count, caret_array); } + + bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const + { return get_mark_glyph_sets ().covers (set_index, glyph_id); } + + /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing + * glyph class and other bits, and high 8-bit the mark attachment type (if any). + * Not to be confused with lookup_props which is very similar. */ + unsigned int get_glyph_props (hb_codepoint_t glyph) const + { + unsigned int klass = get_glyph_class (glyph); + + static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs), ""); + static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures), ""); + static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks), ""); + + switch (klass) { + default: return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED; + case BaseGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH; + case LigatureGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE; + case MarkGlyph: + klass = get_mark_attachment_type (glyph); + return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8); + } + } + + HB_INTERNAL bool is_blocklisted (hb_blob_t *blob, + hb_face_t *face) const; + + struct accelerator_t + { + accelerator_t (hb_face_t *face) + { + table = hb_sanitize_context_t ().reference_table (face); + if (unlikely (table->is_blocklisted (table.get_blob (), face))) + { + hb_blob_destroy (table.get_blob ()); + table = hb_blob_get_empty (); + } + +#ifndef HB_NO_GDEF_CACHE + table->get_mark_glyph_sets ().collect_coverage (mark_glyph_set_digests); +#endif + } + ~accelerator_t () { table.destroy (); } + + unsigned int get_glyph_props (hb_codepoint_t glyph) const + { + unsigned v; + +#ifndef HB_NO_GDEF_CACHE + if (glyph_props_cache.get (glyph, &v)) + return v; +#endif + + v = table->get_glyph_props (glyph); + +#ifndef HB_NO_GDEF_CACHE + if (likely (table.get_blob ())) // Don't try setting if we are the null instance! + glyph_props_cache.set (glyph, v); +#endif + + return v; + + } + + bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const + { + return +#ifndef HB_NO_GDEF_CACHE + mark_glyph_set_digests[set_index].may_have (glyph_id) && +#endif + table->mark_set_covers (set_index, glyph_id); + } + + hb_blob_ptr_t table; +#ifndef HB_NO_GDEF_CACHE + hb_vector_t mark_glyph_set_digests; + mutable hb_cache_t<21, 3, 8> glyph_props_cache; +#endif + }; + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { get_lig_caret_list ().collect_variation_indices (c); } + + protected: + union { + FixedVersion<> version; /* Version identifier */ + GDEFVersion1_2 version1; +#ifndef HB_NO_BEYOND_64K + GDEFVersion1_2 version2; +#endif + } u; + public: + DEFINE_SIZE_MIN (4); +}; + +struct GDEF_accelerator_t : GDEF::accelerator_t { + GDEF_accelerator_t (hb_face_t *face) : GDEF::accelerator_t (face) {} +}; + +} /* namespace OT */ + + +#endif /* OT_LAYOUT_GDEF_GDEF_HH */ diff --git a/libs/harfbuzz/src/OT/Layout/GPOS/Anchor.hh b/libs/harfbuzz/src/OT/Layout/GPOS/Anchor.hh index 49e76e775..7802e397f 100644 --- a/libs/harfbuzz/src/OT/Layout/GPOS/Anchor.hh +++ b/libs/harfbuzz/src/OT/Layout/GPOS/Anchor.hh @@ -25,6 +25,7 @@ struct Anchor { TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return_trace (false); + hb_barrier (); switch (u.format) { case 1: return_trace (u.format1.sanitize (c)); case 2: return_trace (u.format2.sanitize (c)); diff --git a/libs/harfbuzz/src/OT/Layout/GPOS/AnchorFormat3.hh b/libs/harfbuzz/src/OT/Layout/GPOS/AnchorFormat3.hh index 2e30ab33c..b5422652c 100644 --- a/libs/harfbuzz/src/OT/Layout/GPOS/AnchorFormat3.hh +++ b/libs/harfbuzz/src/OT/Layout/GPOS/AnchorFormat3.hh @@ -25,7 +25,9 @@ struct AnchorFormat3 bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this)); + if (unlikely (!c->check_struct (this))) return_trace (false); + + return_trace (xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this)); } void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED, @@ -35,25 +37,35 @@ struct AnchorFormat3 *x = font->em_fscale_x (xCoordinate); *y = font->em_fscale_y (yCoordinate); - if (font->x_ppem || font->num_coords) + if ((font->x_ppem || font->num_coords) && xDeviceTable.sanitize (&c->sanitizer, this)) + { + hb_barrier (); *x += (this+xDeviceTable).get_x_delta (font, c->var_store, c->var_store_cache); - if (font->y_ppem || font->num_coords) + } + if ((font->y_ppem || font->num_coords) && yDeviceTable.sanitize (&c->sanitizer, this)) + { + hb_barrier (); *y += (this+yDeviceTable).get_y_delta (font, c->var_store, c->var_store_cache); + } } bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); auto *out = c->serializer->start_embed (*this); - if (unlikely (!out)) return_trace (false); if (unlikely (!c->serializer->embed (format))) return_trace (false); if (unlikely (!c->serializer->embed (xCoordinate))) return_trace (false); if (unlikely (!c->serializer->embed (yCoordinate))) return_trace (false); unsigned x_varidx = xDeviceTable ? (this+xDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX; - if (c->plan->layout_variation_idx_delta_map->has (x_varidx)) + if (x_varidx != HB_OT_LAYOUT_NO_VARIATIONS_INDEX) { - int delta = hb_second (c->plan->layout_variation_idx_delta_map->get (x_varidx)); + hb_pair_t *new_varidx_delta; + if (!c->plan->layout_variation_idx_delta_map.has (x_varidx, &new_varidx_delta)) + return_trace (false); + + x_varidx = hb_first (*new_varidx_delta); + int delta = hb_second (*new_varidx_delta); if (delta != 0) { if (!c->serializer->check_assign (out->xCoordinate, xCoordinate + delta, @@ -63,9 +75,14 @@ struct AnchorFormat3 } unsigned y_varidx = yDeviceTable ? (this+yDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX; - if (c->plan->layout_variation_idx_delta_map->has (y_varidx)) + if (y_varidx != HB_OT_LAYOUT_NO_VARIATIONS_INDEX) { - int delta = hb_second (c->plan->layout_variation_idx_delta_map->get (y_varidx)); + hb_pair_t *new_varidx_delta; + if (!c->plan->layout_variation_idx_delta_map.has (y_varidx, &new_varidx_delta)) + return_trace (false); + + y_varidx = hb_first (*new_varidx_delta); + int delta = hb_second (*new_varidx_delta); if (delta != 0) { if (!c->serializer->check_assign (out->yCoordinate, yCoordinate + delta, @@ -74,14 +91,17 @@ struct AnchorFormat3 } } - if (c->plan->all_axes_pinned) + /* in case that all axes are pinned or no variations after instantiation, + * both var_idxes will be mapped to HB_OT_LAYOUT_NO_VARIATIONS_INDEX */ + if (x_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX && + y_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX) return_trace (c->serializer->check_assign (out->format, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW)); if (!c->serializer->embed (xDeviceTable)) return_trace (false); if (!c->serializer->embed (yDeviceTable)) return_trace (false); - out->xDeviceTable.serialize_copy (c->serializer, xDeviceTable, this, 0, hb_serialize_context_t::Head, c->plan->layout_variation_idx_delta_map); - out->yDeviceTable.serialize_copy (c->serializer, yDeviceTable, this, 0, hb_serialize_context_t::Head, c->plan->layout_variation_idx_delta_map); + out->xDeviceTable.serialize_copy (c->serializer, xDeviceTable, this, 0, hb_serialize_context_t::Head, &c->plan->layout_variation_idx_delta_map); + out->yDeviceTable.serialize_copy (c->serializer, yDeviceTable, this, 0, hb_serialize_context_t::Head, &c->plan->layout_variation_idx_delta_map); return_trace (out); } diff --git a/libs/harfbuzz/src/OT/Layout/GPOS/AnchorMatrix.hh b/libs/harfbuzz/src/OT/Layout/GPOS/AnchorMatrix.hh index c442efa1e..2557e9a72 100644 --- a/libs/harfbuzz/src/OT/Layout/GPOS/AnchorMatrix.hh +++ b/libs/harfbuzz/src/OT/Layout/GPOS/AnchorMatrix.hh @@ -8,7 +8,7 @@ namespace GPOS_impl { struct AnchorMatrix { HBUINT16 rows; /* Number of rows */ - UnsizedArrayOf> + UnsizedArrayOf> matrixZ; /* Matrix of offsets to Anchor tables-- * from beginning of AnchorMatrix table */ public: @@ -18,21 +18,31 @@ struct AnchorMatrix { TRACE_SANITIZE (this); if (!c->check_struct (this)) return_trace (false); + hb_barrier (); if (unlikely (hb_unsigned_mul_overflows (rows, cols))) return_trace (false); unsigned int count = rows * cols; if (!c->check_array (matrixZ.arrayZ, count)) return_trace (false); + + if (c->lazy_some_gpos) + return_trace (true); + + hb_barrier (); for (unsigned int i = 0; i < count; i++) if (!matrixZ[i].sanitize (c, this)) return_trace (false); return_trace (true); } - const Anchor& get_anchor (unsigned int row, unsigned int col, - unsigned int cols, bool *found) const + const Anchor& get_anchor (hb_ot_apply_context_t *c, + unsigned int row, unsigned int col, + unsigned int cols, bool *found) const { *found = false; if (unlikely (row >= rows || col >= cols)) return Null (Anchor); - *found = !matrixZ[row * cols + col].is_null (); - return this+matrixZ[row * cols + col]; + auto &offset = matrixZ[row * cols + col]; + if (unlikely (!offset.sanitize (&c->sanitizer, this))) return Null (Anchor); + hb_barrier (); + *found = !offset.is_null (); + return this+offset; } template > *layout_variation_idx_delta_map, - bool all_axes_pinned); + unsigned new_format); } diff --git a/libs/harfbuzz/src/OT/Layout/GPOS/CursivePos.hh b/libs/harfbuzz/src/OT/Layout/GPOS/CursivePos.hh index c105cfb09..0105a9b85 100644 --- a/libs/harfbuzz/src/OT/Layout/GPOS/CursivePos.hh +++ b/libs/harfbuzz/src/OT/Layout/GPOS/CursivePos.hh @@ -19,8 +19,8 @@ struct CursivePos template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); default:return_trace (c->default_return_value ()); diff --git a/libs/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh b/libs/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh index 7f58fac8b..6b019ac51 100644 --- a/libs/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh +++ b/libs/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh @@ -11,37 +11,38 @@ struct EntryExitRecord { friend struct CursivePosFormat1; - bool sanitize (hb_sanitize_context_t *c, const void *base) const + bool sanitize (hb_sanitize_context_t *c, const struct CursivePosFormat1 *base) const { TRACE_SANITIZE (this); return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base)); } void collect_variation_indices (hb_collect_variation_indices_context_t *c, - const void *src_base) const + const struct CursivePosFormat1 *src_base) const { (src_base+entryAnchor).collect_variation_indices (c); (src_base+exitAnchor).collect_variation_indices (c); } - EntryExitRecord* subset (hb_subset_context_t *c, - const void *src_base) const + bool subset (hb_subset_context_t *c, + const struct CursivePosFormat1 *src_base) const { TRACE_SERIALIZE (this); auto *out = c->serializer->embed (this); - if (unlikely (!out)) return_trace (nullptr); + if (unlikely (!out)) return_trace (false); - out->entryAnchor.serialize_subset (c, entryAnchor, src_base); - out->exitAnchor.serialize_subset (c, exitAnchor, src_base); - return_trace (out); + bool ret = false; + ret |= out->entryAnchor.serialize_subset (c, entryAnchor, src_base); + ret |= out->exitAnchor.serialize_subset (c, exitAnchor, src_base); + return_trace (ret); } protected: - Offset16To + Offset16To entryAnchor; /* Offset to EntryAnchor table--from * beginning of CursivePos * subtable--may be NULL */ - Offset16To + Offset16To exitAnchor; /* Offset to ExitAnchor table--from * beginning of CursivePos * subtable--may be NULL */ @@ -91,7 +92,13 @@ struct CursivePosFormat1 bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this)); + if (unlikely (!coverage.sanitize (c, this))) + return_trace (false); + + if (c->lazy_some_gpos) + return_trace (entryExitRecord.sanitize_shallow (c)); + else + return_trace (entryExitRecord.sanitize (c, this)); } bool intersects (const hb_set_t *glyphs) const @@ -119,23 +126,27 @@ struct CursivePosFormat1 hb_buffer_t *buffer = c->buffer; const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)]; - if (!this_record.entryAnchor) return_trace (false); + if (!this_record.entryAnchor || + unlikely (!this_record.entryAnchor.sanitize (&c->sanitizer, this))) return_trace (false); + hb_barrier (); hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; - skippy_iter.reset (buffer->idx, 1); + skippy_iter.reset_fast (buffer->idx); unsigned unsafe_from; - if (!skippy_iter.prev (&unsafe_from)) + if (unlikely (!skippy_iter.prev (&unsafe_from))) { buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); return_trace (false); } const EntryExitRecord &prev_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)]; - if (!prev_record.exitAnchor) + if (!prev_record.exitAnchor || + unlikely (!prev_record.exitAnchor.sanitize (&c->sanitizer, this))) { buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); return_trace (false); } + hb_barrier (); unsigned int i = skippy_iter.idx; unsigned int j = buffer->idx; @@ -143,7 +154,7 @@ struct CursivePosFormat1 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "cursive attaching glyph at %d to glyph at %d", + "cursive attaching glyph at %u to glyph at %u", i, j); } @@ -200,8 +211,8 @@ struct CursivePosFormat1 * Arabic. */ unsigned int child = i; unsigned int parent = j; - hb_position_t x_offset = entry_x - exit_x; - hb_position_t y_offset = entry_y - exit_y; + hb_position_t x_offset = roundf (entry_x - exit_x); + hb_position_t y_offset = roundf (entry_y - exit_y); if (!(c->lookup_props & LookupFlag::RightToLeft)) { unsigned int k = child; @@ -241,7 +252,7 @@ struct CursivePosFormat1 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "cursive attached glyph at %d to glyph at %d", + "cursive attached glyph at %u to glyph at %u", i, j); } @@ -253,7 +264,7 @@ struct CursivePosFormat1 hb_requires (hb_is_iterator (Iterator))> void serialize (hb_subset_context_t *c, Iterator it, - const void *src_base) + const struct CursivePosFormat1 *src_base) { if (unlikely (!c->serializer->extend_min ((*this)))) return; this->format = 1; @@ -278,7 +289,6 @@ struct CursivePosFormat1 const hb_map_t &glyph_map = *c->plan->glyph_map; auto *out = c->serializer->start_embed (*this); - if (unlikely (!out)) return_trace (false); auto it = + hb_zip (this+coverage, entryExitRecord) diff --git a/libs/harfbuzz/src/OT/Layout/GPOS/GPOS.hh b/libs/harfbuzz/src/OT/Layout/GPOS/GPOS.hh index 9493ec987..f4af98b25 100644 --- a/libs/harfbuzz/src/OT/Layout/GPOS/GPOS.hh +++ b/libs/harfbuzz/src/OT/Layout/GPOS/GPOS.hh @@ -156,7 +156,7 @@ GPOS::position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer) { for (unsigned i = 0; i < len; i++) if (unlikely (pos[i].y_offset)) - pos[i].x_offset += _hb_roundf (font->slant_xy * pos[i].y_offset); + pos[i].x_offset += roundf (font->slant_xy * pos[i].y_offset); } } diff --git a/libs/harfbuzz/src/OT/Layout/GPOS/LigatureArray.hh b/libs/harfbuzz/src/OT/Layout/GPOS/LigatureArray.hh index a2d807cc3..59cca40aa 100644 --- a/libs/harfbuzz/src/OT/Layout/GPOS/LigatureArray.hh +++ b/libs/harfbuzz/src/OT/Layout/GPOS/LigatureArray.hh @@ -27,6 +27,7 @@ struct LigatureArray : List16OfOffset16To auto *out = c->serializer->start_embed (this); if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + bool ret = false; for (const auto _ : + hb_zip (coverage, *this) | hb_filter (glyphset, hb_first)) { @@ -38,13 +39,13 @@ struct LigatureArray : List16OfOffset16To + hb_range (src.rows * class_count) | hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); }) ; - matrix->serialize_subset (c, - _.second, - this, - src.rows, - indexes); + ret |= matrix->serialize_subset (c, + _.second, + this, + src.rows, + indexes); } - return_trace (this->len); + return_trace (ret); } }; diff --git a/libs/harfbuzz/src/OT/Layout/GPOS/MarkArray.hh b/libs/harfbuzz/src/OT/Layout/GPOS/MarkArray.hh index cb5e8b268..0887cc158 100644 --- a/libs/harfbuzz/src/OT/Layout/GPOS/MarkArray.hh +++ b/libs/harfbuzz/src/OT/Layout/GPOS/MarkArray.hh @@ -28,7 +28,7 @@ struct MarkArray : Array16Of /* Array of MarkRecords--in Cove const Anchor& mark_anchor = this + record.markAnchor; bool found; - const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found); + const Anchor& glyph_anchor = anchors.get_anchor (c, glyph_index, mark_class, class_count, &found); /* If this subtable doesn't have an anchor for this base and this class, * return false such that the subsequent subtables have a chance at it. */ if (unlikely (!found)) return_trace (false); @@ -42,7 +42,7 @@ struct MarkArray : Array16Of /* Array of MarkRecords--in Cove if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "attaching mark glyph at %d to glyph at %d", + "attaching mark glyph at %u to glyph at %u", c->buffer->idx, glyph_pos); } @@ -56,7 +56,7 @@ struct MarkArray : Array16Of /* Array of MarkRecords--in Cove if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "attached mark glyph at %d to glyph at %d", + "attached mark glyph at %u to glyph at %u", c->buffer->idx, glyph_pos); } @@ -82,10 +82,10 @@ struct MarkArray : Array16Of /* Array of MarkRecords--in Cove | hb_map (hb_second) ; + bool ret = false; unsigned new_length = 0; for (const auto& mark_record : mark_iter) { - if (unlikely (!mark_record.subset (c, this, klass_mapping))) - return_trace (false); + ret |= mark_record.subset (c, this, klass_mapping); new_length++; } @@ -93,7 +93,7 @@ struct MarkArray : Array16Of /* Array of MarkRecords--in Cove HB_SERIALIZE_ERROR_ARRAY_OVERFLOW))) return_trace (false); - return_trace (true); + return_trace (ret); } }; diff --git a/libs/harfbuzz/src/OT/Layout/GPOS/MarkBasePos.hh b/libs/harfbuzz/src/OT/Layout/GPOS/MarkBasePos.hh index c99b6b2e4..cd2fc7ccf 100644 --- a/libs/harfbuzz/src/OT/Layout/GPOS/MarkBasePos.hh +++ b/libs/harfbuzz/src/OT/Layout/GPOS/MarkBasePos.hh @@ -13,7 +13,7 @@ struct MarkBasePos union { HBUINT16 format; /* Format identifier */ MarkBasePosFormat1_2 format1; -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K MarkBasePosFormat1_2 format2; #endif } u; @@ -22,11 +22,11 @@ struct MarkBasePos template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); #endif default:return_trace (c->default_return_value ()); diff --git a/libs/harfbuzz/src/OT/Layout/GPOS/MarkBasePosFormat1.hh b/libs/harfbuzz/src/OT/Layout/GPOS/MarkBasePosFormat1.hh index ebb8c31c6..1b8f3c80a 100644 --- a/libs/harfbuzz/src/OT/Layout/GPOS/MarkBasePosFormat1.hh +++ b/libs/harfbuzz/src/OT/Layout/GPOS/MarkBasePosFormat1.hh @@ -90,6 +90,25 @@ struct MarkBasePosFormat1_2 const Coverage &get_coverage () const { return this+markCoverage; } + static inline bool accept (hb_buffer_t *buffer, unsigned idx) + { + /* We only want to attach to the first of a MultipleSubst sequence. + * https://github.com/harfbuzz/harfbuzz/issues/740 + * Reject others... + * ...but stop if we find a mark in the MultipleSubst sequence: + * https://github.com/harfbuzz/harfbuzz/issues/1020 */ + return !_hb_glyph_info_multiplied (&buffer->info[idx]) || + 0 == _hb_glyph_info_get_lig_comp (&buffer->info[idx]) || + (idx == 0 || + _hb_glyph_info_is_mark (&buffer->info[idx - 1]) || + !_hb_glyph_info_multiplied (&buffer->info[idx - 1]) || + _hb_glyph_info_get_lig_id (&buffer->info[idx]) != + _hb_glyph_info_get_lig_id (&buffer->info[idx - 1]) || + _hb_glyph_info_get_lig_comp (&buffer->info[idx]) != + _hb_glyph_info_get_lig_comp (&buffer->info[idx - 1]) + 1 + ); + } + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); @@ -97,48 +116,54 @@ struct MarkBasePosFormat1_2 unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint); if (likely (mark_index == NOT_COVERED)) return_trace (false); - /* Now we search backwards for a non-mark glyph */ + /* Now we search backwards for a non-mark glyph. + * We don't use skippy_iter.prev() to avoid O(n^2) behavior. */ + hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; - skippy_iter.reset (buffer->idx, 1); skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); - do { - unsigned unsafe_from; - if (!skippy_iter.prev (&unsafe_from)) + + if (c->last_base_until > buffer->idx) + { + c->last_base_until = 0; + c->last_base = -1; + } + unsigned j; + for (j = buffer->idx; j > c->last_base_until; j--) + { + auto match = skippy_iter.match (buffer->info[j - 1]); + if (match == skippy_iter.MATCH) { - buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); - return_trace (false); + // https://github.com/harfbuzz/harfbuzz/issues/4124 + if (!accept (buffer, j - 1) && + NOT_COVERED == (this+baseCoverage).get_coverage (buffer->info[j - 1].codepoint)) + match = skippy_iter.SKIP; } + if (match == skippy_iter.MATCH) + { + c->last_base = (signed) j - 1; + break; + } + } + c->last_base_until = buffer->idx; + if (c->last_base == -1) + { + buffer->unsafe_to_concat_from_outbuffer (0, buffer->idx + 1); + return_trace (false); + } - /* We only want to attach to the first of a MultipleSubst sequence. - * https://github.com/harfbuzz/harfbuzz/issues/740 - * Reject others... - * ...but stop if we find a mark in the MultipleSubst sequence: - * https://github.com/harfbuzz/harfbuzz/issues/1020 */ - if (!_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx]) || - 0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) || - (skippy_iter.idx == 0 || - _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx - 1]) || - !_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx - 1]) || - _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]) != - _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx - 1]) || - _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) != - _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx - 1]) + 1 - )) - break; - skippy_iter.reject (); - } while (true); + unsigned idx = (unsigned) c->last_base; /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */ - //if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { return_trace (false); } + //if (!_hb_glyph_info_is_base_glyph (&buffer->info[idx])) { return_trace (false); } - unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[skippy_iter.idx].codepoint); + unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[idx].codepoint); if (base_index == NOT_COVERED) { - buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); + buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1); return_trace (false); } - return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx)); + return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, idx)); } bool subset (hb_subset_context_t *c) const @@ -172,9 +197,10 @@ struct MarkBasePosFormat1_2 if (!out->markCoverage.serialize_serialize (c->serializer, new_coverage.iter ())) return_trace (false); - out->markArray.serialize_subset (c, markArray, this, - (this+markCoverage).iter (), - &klass_mapping); + if (unlikely (!out->markArray.serialize_subset (c, markArray, this, + (this+markCoverage).iter (), + &klass_mapping))) + return_trace (false); unsigned basecount = (this+baseArray).rows; auto base_iter = @@ -203,11 +229,9 @@ struct MarkBasePosFormat1_2 ; } - out->baseArray.serialize_subset (c, baseArray, this, - base_iter.len (), - base_indexes.iter ()); - - return_trace (true); + return_trace (out->baseArray.serialize_subset (c, baseArray, this, + base_iter.len (), + base_indexes.iter ())); } }; diff --git a/libs/harfbuzz/src/OT/Layout/GPOS/MarkLigPos.hh b/libs/harfbuzz/src/OT/Layout/GPOS/MarkLigPos.hh index 8a4de9ffa..739c32541 100644 --- a/libs/harfbuzz/src/OT/Layout/GPOS/MarkLigPos.hh +++ b/libs/harfbuzz/src/OT/Layout/GPOS/MarkLigPos.hh @@ -13,7 +13,7 @@ struct MarkLigPos union { HBUINT16 format; /* Format identifier */ MarkLigPosFormat1_2 format1; -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K MarkLigPosFormat1_2 format2; #endif } u; @@ -22,11 +22,11 @@ struct MarkLigPos template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); #endif default:return_trace (c->default_return_value ()); diff --git a/libs/harfbuzz/src/OT/Layout/GPOS/MarkLigPosFormat1.hh b/libs/harfbuzz/src/OT/Layout/GPOS/MarkLigPosFormat1.hh index 1a8021237..d6bee277c 100644 --- a/libs/harfbuzz/src/OT/Layout/GPOS/MarkLigPosFormat1.hh +++ b/libs/harfbuzz/src/OT/Layout/GPOS/MarkLigPosFormat1.hh @@ -100,24 +100,41 @@ struct MarkLigPosFormat1_2 if (likely (mark_index == NOT_COVERED)) return_trace (false); /* Now we search backwards for a non-mark glyph */ + hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; - skippy_iter.reset (buffer->idx, 1); skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); - unsigned unsafe_from; - if (!skippy_iter.prev (&unsafe_from)) + + if (c->last_base_until > buffer->idx) + { + c->last_base_until = 0; + c->last_base = -1; + } + unsigned j; + for (j = buffer->idx; j > c->last_base_until; j--) { - buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); + auto match = skippy_iter.match (buffer->info[j - 1]); + if (match == skippy_iter.MATCH) + { + c->last_base = (signed) j - 1; + break; + } + } + c->last_base_until = buffer->idx; + if (c->last_base == -1) + { + buffer->unsafe_to_concat_from_outbuffer (0, buffer->idx + 1); return_trace (false); } + unsigned idx = (unsigned) c->last_base; + /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */ - //if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); } + //if (!_hb_glyph_info_is_ligature (&buffer->info[idx])) { return_trace (false); } - unsigned int j = skippy_iter.idx; - unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[j].codepoint); + unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[idx].codepoint); if (lig_index == NOT_COVERED) { - buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); + buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1); return_trace (false); } @@ -128,7 +145,7 @@ struct MarkLigPosFormat1_2 unsigned int comp_count = lig_attach.rows; if (unlikely (!comp_count)) { - buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); + buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1); return_trace (false); } @@ -137,7 +154,7 @@ struct MarkLigPosFormat1_2 * can directly use the component index. If not, we attach the mark * glyph to the last component of the ligature. */ unsigned int comp_index; - unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]); + unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[idx]); unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur()); unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur()); if (lig_id && lig_id == mark_id && mark_comp > 0) @@ -145,14 +162,14 @@ struct MarkLigPosFormat1_2 else comp_index = comp_count - 1; - return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j)); + return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, idx)); } bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - const hb_map_t &glyph_map = *c->plan->glyph_map; + const hb_map_t &glyph_map = c->plan->glyph_map_gsub; auto *out = c->serializer->start_embed (*this); if (unlikely (!c->serializer->extend_min (out))) return_trace (false); @@ -178,23 +195,24 @@ struct MarkLigPosFormat1_2 if (!out->markCoverage.serialize_serialize (c->serializer, new_mark_coverage)) return_trace (false); - out->markArray.serialize_subset (c, markArray, this, - (this+markCoverage).iter (), - &klass_mapping); + if (unlikely (!out->markArray.serialize_subset (c, markArray, this, + (this+markCoverage).iter (), + &klass_mapping))) + return_trace (false); auto new_ligature_coverage = + hb_iter (this + ligatureCoverage) - | hb_filter (glyphset) + | hb_take ((this + ligatureArray).len) | hb_map_retains_sorting (glyph_map) + | hb_filter ([] (hb_codepoint_t glyph) { return glyph != HB_MAP_VALUE_INVALID; }) ; if (!out->ligatureCoverage.serialize_serialize (c->serializer, new_ligature_coverage)) return_trace (false); - out->ligatureArray.serialize_subset (c, ligatureArray, this, - hb_iter (this+ligatureCoverage), classCount, &klass_mapping); - - return_trace (true); + return_trace (out->ligatureArray.serialize_subset (c, ligatureArray, this, + hb_iter (this+ligatureCoverage), + classCount, &klass_mapping)); } }; diff --git a/libs/harfbuzz/src/OT/Layout/GPOS/MarkMarkPos.hh b/libs/harfbuzz/src/OT/Layout/GPOS/MarkMarkPos.hh index 74b5105c4..cddd2a3d5 100644 --- a/libs/harfbuzz/src/OT/Layout/GPOS/MarkMarkPos.hh +++ b/libs/harfbuzz/src/OT/Layout/GPOS/MarkMarkPos.hh @@ -13,7 +13,7 @@ struct MarkMarkPos union { HBUINT16 format; /* Format identifier */ MarkMarkPosFormat1_2 format1; -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K MarkMarkPosFormat1_2 format2; #endif } u; @@ -22,11 +22,11 @@ struct MarkMarkPos template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); #endif default:return_trace (c->default_return_value ()); diff --git a/libs/harfbuzz/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh b/libs/harfbuzz/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh index fbcebb804..57eb782a9 100644 --- a/libs/harfbuzz/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh +++ b/libs/harfbuzz/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh @@ -42,6 +42,7 @@ struct MarkMarkPosFormat1_2 mark1Coverage.sanitize (c, this) && mark2Coverage.sanitize (c, this) && mark1Array.sanitize (c, this) && + hb_barrier () && mark2Array.sanitize (c, this, (unsigned int) classCount)); } @@ -100,16 +101,16 @@ struct MarkMarkPosFormat1_2 /* now we search backwards for a suitable mark glyph until a non-mark glyph */ hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; - skippy_iter.reset (buffer->idx, 1); + skippy_iter.reset_fast (buffer->idx); skippy_iter.set_lookup_props (c->lookup_props & ~(uint32_t)LookupFlag::IgnoreFlags); unsigned unsafe_from; - if (!skippy_iter.prev (&unsafe_from)) + if (unlikely (!skippy_iter.prev (&unsafe_from))) { buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); return_trace (false); } - if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) + if (likely (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]))) { buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); return_trace (false); @@ -183,9 +184,10 @@ struct MarkMarkPosFormat1_2 if (!out->mark1Coverage.serialize_serialize (c->serializer, new_coverage.iter ())) return_trace (false); - out->mark1Array.serialize_subset (c, mark1Array, this, - (this+mark1Coverage).iter (), - &klass_mapping); + if (unlikely (!out->mark1Array.serialize_subset (c, mark1Array, this, + (this+mark1Coverage).iter (), + &klass_mapping))) + return_trace (false); unsigned mark2count = (this+mark2Array).rows; auto mark2_iter = @@ -214,9 +216,10 @@ struct MarkMarkPosFormat1_2 ; } - out->mark2Array.serialize_subset (c, mark2Array, this, mark2_iter.len (), mark2_indexes.iter ()); + return_trace (out->mark2Array.serialize_subset (c, mark2Array, this, + mark2_iter.len (), + mark2_indexes.iter ())); - return_trace (true); } }; diff --git a/libs/harfbuzz/src/OT/Layout/GPOS/MarkRecord.hh b/libs/harfbuzz/src/OT/Layout/GPOS/MarkRecord.hh index a7d489d2a..3d11c7773 100644 --- a/libs/harfbuzz/src/OT/Layout/GPOS/MarkRecord.hh +++ b/libs/harfbuzz/src/OT/Layout/GPOS/MarkRecord.hh @@ -24,17 +24,16 @@ struct MarkRecord return_trace (c->check_struct (this) && markAnchor.sanitize (c, base)); } - MarkRecord *subset (hb_subset_context_t *c, - const void *src_base, - const hb_map_t *klass_mapping) const + bool subset (hb_subset_context_t *c, + const void *src_base, + const hb_map_t *klass_mapping) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); - if (unlikely (!out)) return_trace (nullptr); + if (unlikely (!out)) return_trace (false); out->klass = klass_mapping->get (klass); - out->markAnchor.serialize_subset (c, markAnchor, src_base); - return_trace (out); + return_trace (out->markAnchor.serialize_subset (c, markAnchor, src_base)); } void collect_variation_indices (hb_collect_variation_indices_context_t *c, diff --git a/libs/harfbuzz/src/OT/Layout/GPOS/PairPos.hh b/libs/harfbuzz/src/OT/Layout/GPOS/PairPos.hh index 72bfc43dc..c13d4f489 100644 --- a/libs/harfbuzz/src/OT/Layout/GPOS/PairPos.hh +++ b/libs/harfbuzz/src/OT/Layout/GPOS/PairPos.hh @@ -15,7 +15,7 @@ struct PairPos HBUINT16 format; /* Format identifier */ PairPosFormat1_3 format1; PairPosFormat2_4 format2; -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K PairPosFormat1_3 format3; PairPosFormat2_4 format4; #endif @@ -25,12 +25,12 @@ struct PairPos template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K case 3: return_trace (c->dispatch (u.format3, std::forward (ds)...)); case 4: return_trace (c->dispatch (u.format4, std::forward (ds)...)); #endif diff --git a/libs/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh b/libs/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh index ddf7313f9..ac2774a76 100644 --- a/libs/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh +++ b/libs/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh @@ -36,6 +36,7 @@ struct PairPosFormat1_3 TRACE_SANITIZE (this); if (!c->check_struct (this)) return_trace (false); + hb_barrier (); unsigned int len1 = valueFormat[0].get_len (); unsigned int len2 = valueFormat[1].get_len (); @@ -43,7 +44,7 @@ struct PairPosFormat1_3 { valueFormat, len1, - 1 + len1 + len2 + PairSet::get_size (len1, len2) }; return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure)); @@ -51,8 +52,21 @@ struct PairPosFormat1_3 bool intersects (const hb_set_t *glyphs) const { + auto &cov = this+coverage; + + if (pairSet.len > glyphs->get_population () * hb_bit_storage ((unsigned) pairSet.len) / 4) + { + for (hb_codepoint_t g : glyphs->iter()) + { + unsigned i = cov.get_coverage (g); + if ((this+pairSet[i]).intersects (glyphs, valueFormat)) + return true; + } + return false; + } + return - + hb_zip (this+coverage, pairSet) + + hb_zip (cov, pairSet) | hb_filter (*glyphs, hb_first) | hb_map (hb_second) | hb_map ([glyphs, this] (const typename Types::template OffsetTo &_) @@ -97,9 +111,9 @@ struct PairPosFormat1_3 if (likely (index == NOT_COVERED)) return_trace (false); hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; - skippy_iter.reset (buffer->idx, 1); + skippy_iter.reset_fast (buffer->idx); unsigned unsafe_to; - if (!skippy_iter.next (&unsafe_to)) + if (unlikely (!skippy_iter.next (&unsafe_to))) { buffer->unsafe_to_concat (buffer->idx, unsafe_to); return_trace (false); @@ -118,20 +132,33 @@ struct PairPosFormat1_3 auto *out = c->serializer->start_embed (*this); if (unlikely (!c->serializer->extend_min (out))) return_trace (false); out->format = format; - out->valueFormat[0] = valueFormat[0]; - out->valueFormat[1] = valueFormat[1]; - if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING) + + hb_pair_t newFormats = hb_pair (valueFormat[0], valueFormat[1]); + + if (c->plan->normalized_coords) { - hb_pair_t newFormats = compute_effective_value_formats (glyphset); - out->valueFormat[0] = newFormats.first; - out->valueFormat[1] = newFormats.second; + /* all device flags will be dropped when full instancing, no need to strip + * hints, also do not strip emtpy cause we don't compute the new default + * value during stripping */ + newFormats = compute_effective_value_formats (glyphset, false, false, &c->plan->layout_variation_idx_delta_map); } - - if (c->plan->all_axes_pinned) + /* do not strip hints for VF */ + else if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING) { - out->valueFormat[0] = out->valueFormat[0].drop_device_table_flags (); - out->valueFormat[1] = out->valueFormat[1].drop_device_table_flags (); + hb_blob_t* blob = hb_face_reference_table (c->plan->source, HB_TAG ('f','v','a','r')); + bool has_fvar = (blob != hb_blob_get_empty ()); + hb_blob_destroy (blob); + + bool strip = !has_fvar; + /* special case: strip hints when a VF has no GDEF varstore after + * subsetting*/ + if (has_fvar && !c->plan->has_gdef_varstore) + strip = true; + newFormats = compute_effective_value_formats (glyphset, strip, true); } + + out->valueFormat[0] = newFormats.first; + out->valueFormat[1] = newFormats.second; hb_sorted_vector_t new_coverage; @@ -162,29 +189,36 @@ struct PairPosFormat1_3 } - hb_pair_t compute_effective_value_formats (const hb_set_t& glyphset) const + hb_pair_t compute_effective_value_formats (const hb_set_t& glyphset, + bool strip_hints, bool strip_empty, + const hb_hashmap_t> *varidx_delta_map = nullptr) const { - unsigned len1 = valueFormat[0].get_len (); - unsigned len2 = valueFormat[1].get_len (); - unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2); + unsigned record_size = PairSet::get_size (valueFormat); unsigned format1 = 0; unsigned format2 = 0; for (const auto & _ : - + hb_zip (this+coverage, pairSet) | hb_filter (glyphset, hb_first) | hb_map (hb_second)) + + hb_zip (this+coverage, pairSet) + | hb_filter (glyphset, hb_first) + | hb_map (hb_second) + ) { const PairSet& set = (this + _); const PairValueRecord *record = &set.firstPairValueRecord; - for (unsigned i = 0; i < set.len; i++) + unsigned count = set.len; + for (unsigned i = 0; i < count; i++) { if (record->intersects (glyphset)) { - format1 = format1 | valueFormat[0].get_effective_format (record->get_values_1 ()); - format2 = format2 | valueFormat[1].get_effective_format (record->get_values_2 (valueFormat[0])); + format1 = format1 | valueFormat[0].get_effective_format (record->get_values_1 (), strip_hints, strip_empty, &set, varidx_delta_map); + format2 = format2 | valueFormat[1].get_effective_format (record->get_values_2 (valueFormat[0]), strip_hints, strip_empty, &set, varidx_delta_map); } record = &StructAtOffset (record, record_size); } + + if (format1 == valueFormat[0] && format2 == valueFormat[1]) + break; } return hb_pair (format1, format2); diff --git a/libs/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh b/libs/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh index 83b093b98..5ffeb5d0c 100644 --- a/libs/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh +++ b/libs/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh @@ -8,7 +8,7 @@ namespace Layout { namespace GPOS_impl { template -struct PairPosFormat2_4 +struct PairPosFormat2_4 : ValueBase { protected: HBUINT16 format; /* Format identifier--format = 2 */ @@ -49,14 +49,14 @@ struct PairPosFormat2_4 unsigned int len1 = valueFormat1.get_len (); unsigned int len2 = valueFormat2.get_len (); - unsigned int stride = len1 + len2; - unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size (); + unsigned int stride = HBUINT16::static_size * (len1 + len2); unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count; return_trace (c->check_range ((const void *) values, count, - record_size) && - valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) && - valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride)); + stride) && + (c->lazy_some_gpos || + (valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) && + valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride)))); } bool intersects (const hb_set_t *glyphs) const @@ -131,18 +131,14 @@ struct PairPosFormat2_4 if (likely (index == NOT_COVERED)) return_trace (false); hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; - skippy_iter.reset (buffer->idx, 1); + skippy_iter.reset_fast (buffer->idx); unsigned unsafe_to; - if (!skippy_iter.next (&unsafe_to)) + if (unlikely (!skippy_iter.next (&unsafe_to))) { buffer->unsafe_to_concat (buffer->idx, unsafe_to); return_trace (false); } - unsigned int len1 = valueFormat1.get_len (); - unsigned int len2 = valueFormat2.get_len (); - unsigned int record_len = len1 + len2; - unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint); unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint); if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) @@ -151,20 +147,24 @@ struct PairPosFormat2_4 return_trace (false); } + unsigned int len1 = valueFormat1.get_len (); + unsigned int len2 = valueFormat2.get_len (); + unsigned int record_len = len1 + len2; + const Value *v = &values[record_len * (klass1 * class2Count + klass2)]; bool applied_first = false, applied_second = false; /* Isolate simple kerning and apply it half to each side. - * Results in better cursor positinoing / underline drawing. + * Results in better cursor positioning / underline drawing. * * Disabled, because causes issues... :-( * https://github.com/harfbuzz/harfbuzz/issues/3408 * https://github.com/harfbuzz/harfbuzz/pull/3235#issuecomment-1029814978 */ #ifndef HB_SPLIT_KERN - if (0) + if (false) #endif { if (!len2) @@ -220,17 +220,25 @@ struct PairPosFormat2_4 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "kerning glyphs at %d,%d", + "try kerning glyphs at %u,%u", c->buffer->idx, skippy_iter.idx); } - applied_first = valueFormat1.apply_value (c, this, v, buffer->cur_pos()); - applied_second = valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]); + applied_first = len1 && valueFormat1.apply_value (c, this, v, buffer->cur_pos()); + applied_second = len2 && valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]); + + if (applied_first || applied_second) + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->message (c->font, + "kerned glyphs at %u,%u", + c->buffer->idx, skippy_iter.idx); + } if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "kerned glyphs at %d,%d", + "tried kerning glyphs at %u,%u", c->buffer->idx, skippy_iter.idx); } @@ -241,10 +249,15 @@ struct PairPosFormat2_4 boring: buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1); + if (len2) + { + skippy_iter.idx++; + // https://github.com/harfbuzz/harfbuzz/issues/3824 + // https://github.com/harfbuzz/harfbuzz/issues/3888#issuecomment-1326781116 + buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1); + } buffer->idx = skippy_iter.idx; - if (len2) - buffer->idx++; return_trace (true); } @@ -268,47 +281,56 @@ struct PairPosFormat2_4 unsigned len2 = valueFormat2.get_len (); hb_pair_t newFormats = hb_pair (valueFormat1, valueFormat2); - if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING) - newFormats = compute_effective_value_formats (klass1_map, klass2_map); - out->valueFormat1 = newFormats.first; - out->valueFormat2 = newFormats.second; - - if (c->plan->all_axes_pinned) + if (c->plan->normalized_coords) + { + /* in case of full instancing, all var device flags will be dropped so no + * need to strip hints here */ + newFormats = compute_effective_value_formats (klass1_map, klass2_map, false, false, &c->plan->layout_variation_idx_delta_map); + } + /* do not strip hints for VF */ + else if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING) { - out->valueFormat1 = out->valueFormat1.drop_device_table_flags (); - out->valueFormat2 = out->valueFormat2.drop_device_table_flags (); + hb_blob_t* blob = hb_face_reference_table (c->plan->source, HB_TAG ('f','v','a','r')); + bool has_fvar = (blob != hb_blob_get_empty ()); + hb_blob_destroy (blob); + + bool strip = !has_fvar; + /* special case: strip hints when a VF has no GDEF varstore after + * subsetting*/ + if (has_fvar && !c->plan->has_gdef_varstore) + strip = true; + newFormats = compute_effective_value_formats (klass1_map, klass2_map, strip, true); } + out->valueFormat1 = newFormats.first; + out->valueFormat2 = newFormats.second; + + unsigned total_len = len1 + len2; + hb_vector_t class2_idxs (+ hb_range ((unsigned) class2Count) | hb_filter (klass2_map)); for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map)) { - for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map)) + for (unsigned class2_idx : class2_idxs) { - unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2); - valueFormat1.copy_values (c->serializer, out->valueFormat1, this, &values[idx], c->plan->layout_variation_idx_delta_map); - valueFormat2.copy_values (c->serializer, out->valueFormat2, this, &values[idx + len1], c->plan->layout_variation_idx_delta_map); + unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * total_len; + valueFormat1.copy_values (c->serializer, out->valueFormat1, this, &values[idx], &c->plan->layout_variation_idx_delta_map); + valueFormat2.copy_values (c->serializer, out->valueFormat2, this, &values[idx + len1], &c->plan->layout_variation_idx_delta_map); } } - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - const hb_map_t &glyph_map = *c->plan->glyph_map; - - auto it = - + hb_iter (this+coverage) - | hb_filter (glyphset) - | hb_map_retains_sorting (glyph_map) - ; - - out->coverage.serialize_serialize (c->serializer, it); - return_trace (out->class1Count && out->class2Count && bool (it)); + bool ret = out->coverage.serialize_subset(c, coverage, this); + return_trace (out->class1Count && out->class2Count && ret); } hb_pair_t compute_effective_value_formats (const hb_map_t& klass1_map, - const hb_map_t& klass2_map) const + const hb_map_t& klass2_map, + bool strip_hints, bool strip_empty, + const hb_hashmap_t> *varidx_delta_map = nullptr) const { unsigned len1 = valueFormat1.get_len (); unsigned len2 = valueFormat2.get_len (); + unsigned record_size = len1 + len2; unsigned format1 = 0; unsigned format2 = 0; @@ -317,10 +339,13 @@ struct PairPosFormat2_4 { for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map)) { - unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2); - format1 = format1 | valueFormat1.get_effective_format (&values[idx]); - format2 = format2 | valueFormat2.get_effective_format (&values[idx + len1]); + unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * record_size; + format1 = format1 | valueFormat1.get_effective_format (&values[idx], strip_hints, strip_empty, this, varidx_delta_map); + format2 = format2 | valueFormat2.get_effective_format (&values[idx + len1], strip_hints, strip_empty, this, varidx_delta_map); } + + if (format1 == valueFormat1 && format2 == valueFormat2) + break; } return hb_pair (format1, format2); diff --git a/libs/harfbuzz/src/OT/Layout/GPOS/PairSet.hh b/libs/harfbuzz/src/OT/Layout/GPOS/PairSet.hh index aa48d933c..5560fab17 100644 --- a/libs/harfbuzz/src/OT/Layout/GPOS/PairSet.hh +++ b/libs/harfbuzz/src/OT/Layout/GPOS/PairSet.hh @@ -9,7 +9,7 @@ namespace GPOS_impl { template -struct PairSet +struct PairSet : ValueBase { template friend struct PairPosFormat1_3; @@ -24,34 +24,45 @@ struct PairSet public: DEFINE_SIZE_MIN (2); + static unsigned get_size (unsigned len1, unsigned len2) + { + return Types::HBGlyphID::static_size + Value::static_size * (len1 + len2); + } + static unsigned get_size (const ValueFormat valueFormats[2]) + { + unsigned len1 = valueFormats[0].get_len (); + unsigned len2 = valueFormats[1].get_len (); + return get_size (len1, len2); + } + struct sanitize_closure_t { const ValueFormat *valueFormats; unsigned int len1; /* valueFormats[0].get_len() */ - unsigned int stride; /* 1 + len1 + len2 */ + unsigned int stride; /* bytes */ }; bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const { TRACE_SANITIZE (this); - if (!(c->check_struct (this) - && c->check_range (&firstPairValueRecord, + if (!(c->check_struct (this) && + hb_barrier () && + c->check_range (&firstPairValueRecord, len, - HBUINT16::static_size, closure->stride))) return_trace (false); + hb_barrier (); unsigned int count = len; const PairValueRecord *record = &firstPairValueRecord; - return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) && - closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride)); + return_trace (c->lazy_some_gpos || + (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) && + closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride))); } bool intersects (const hb_set_t *glyphs, const ValueFormat *valueFormats) const { - unsigned int len1 = valueFormats[0].get_len (); - unsigned int len2 = valueFormats[1].get_len (); - unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2); + unsigned record_size = get_size (valueFormats); const PairValueRecord *record = &firstPairValueRecord; unsigned int count = len; @@ -67,9 +78,7 @@ struct PairSet void collect_glyphs (hb_collect_glyphs_context_t *c, const ValueFormat *valueFormats) const { - unsigned int len1 = valueFormats[0].get_len (); - unsigned int len2 = valueFormats[1].get_len (); - unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2); + unsigned record_size = get_size (valueFormats); const PairValueRecord *record = &firstPairValueRecord; c->input->add_array (&record->secondGlyph, len, record_size); @@ -78,9 +87,7 @@ struct PairSet void collect_variation_indices (hb_collect_variation_indices_context_t *c, const ValueFormat *valueFormats) const { - unsigned len1 = valueFormats[0].get_len (); - unsigned len2 = valueFormats[1].get_len (); - unsigned record_size = HBUINT16::static_size * (1 + len1 + len2); + unsigned record_size = get_size (valueFormats); const PairValueRecord *record = &firstPairValueRecord; unsigned count = len; @@ -101,7 +108,7 @@ struct PairSet hb_buffer_t *buffer = c->buffer; unsigned int len1 = valueFormats[0].get_len (); unsigned int len2 = valueFormats[1].get_len (); - unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2); + unsigned record_size = get_size (len1, len2); const PairValueRecord *record = hb_bsearch (buffer->info[pos].codepoint, &firstPairValueRecord, @@ -112,24 +119,38 @@ struct PairSet if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "kerning glyphs at %d,%d", + "try kerning glyphs at %u,%u", c->buffer->idx, pos); } - bool applied_first = valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos()); - bool applied_second = valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]); + bool applied_first = len1 && valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos()); + bool applied_second = len2 && valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]); + + if (applied_first || applied_second) + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->message (c->font, + "kerned glyphs at %u,%u", + c->buffer->idx, pos); + } if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "kerned glyphs at %d,%d", + "tried kerning glyphs at %u,%u", c->buffer->idx, pos); } if (applied_first || applied_second) buffer->unsafe_to_break (buffer->idx, pos + 1); + if (len2) - pos++; + { + pos++; + // https://github.com/harfbuzz/harfbuzz/issues/3824 + // https://github.com/harfbuzz/harfbuzz/issues/3888#issuecomment-1326781116 + buffer->unsafe_to_break (buffer->idx, pos + 1); + } buffer->idx = pos; return_trace (true); @@ -154,7 +175,7 @@ struct PairSet unsigned len1 = valueFormats[0].get_len (); unsigned len2 = valueFormats[1].get_len (); - unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2); + unsigned record_size = get_size (len1, len2); typename PairValueRecord::context_t context = { @@ -163,7 +184,7 @@ struct PairSet newFormats, len1, &glyph_map, - c->plan->layout_variation_idx_delta_map + &c->plan->layout_variation_idx_delta_map }; const PairValueRecord *record = &firstPairValueRecord; diff --git a/libs/harfbuzz/src/OT/Layout/GPOS/PairValueRecord.hh b/libs/harfbuzz/src/OT/Layout/GPOS/PairValueRecord.hh index 322247776..d00618b76 100644 --- a/libs/harfbuzz/src/OT/Layout/GPOS/PairValueRecord.hh +++ b/libs/harfbuzz/src/OT/Layout/GPOS/PairValueRecord.hh @@ -22,14 +22,14 @@ struct PairValueRecord ValueRecord values; /* Positioning data for the first glyph * followed by for second glyph */ public: - DEFINE_SIZE_ARRAY (Types::size, values); + DEFINE_SIZE_ARRAY (Types::HBGlyphID::static_size, values); int cmp (hb_codepoint_t k) const { return secondGlyph.cmp (k); } struct context_t { - const void *base; + const ValueBase *base; const ValueFormat *valueFormats; const ValueFormat *newFormats; unsigned len1; /* valueFormats[0].get_len() */ @@ -62,7 +62,7 @@ struct PairValueRecord void collect_variation_indices (hb_collect_variation_indices_context_t *c, const ValueFormat *valueFormats, - const void *base) const + const ValueBase *base) const { unsigned record1_len = valueFormats[0].get_len (); unsigned record2_len = valueFormats[1].get_len (); diff --git a/libs/harfbuzz/src/OT/Layout/GPOS/SinglePos.hh b/libs/harfbuzz/src/OT/Layout/GPOS/SinglePos.hh index 6dce3e634..a0243a218 100644 --- a/libs/harfbuzz/src/OT/Layout/GPOS/SinglePos.hh +++ b/libs/harfbuzz/src/OT/Layout/GPOS/SinglePos.hh @@ -39,14 +39,12 @@ struct SinglePos const SrcLookup* src, Iterator glyph_val_iter_pairs, const hb_hashmap_t> *layout_variation_idx_delta_map, - bool all_axes_pinned) + unsigned newFormat) { if (unlikely (!c->extend_min (u.format))) return; unsigned format = 2; - ValueFormat new_format = src->get_value_format (); - - if (all_axes_pinned) - new_format = new_format.drop_device_table_flags (); + ValueFormat new_format; + new_format = newFormat; if (glyph_val_iter_pairs) format = get_format (glyph_val_iter_pairs); @@ -72,8 +70,8 @@ struct SinglePos template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); @@ -89,8 +87,8 @@ SinglePos_serialize (hb_serialize_context_t *c, const SrcLookup *src, Iterator it, const hb_hashmap_t> *layout_variation_idx_delta_map, - bool all_axes_pinned) -{ c->start_embed ()->serialize (c, src, it, layout_variation_idx_delta_map, all_axes_pinned); } + unsigned new_format) +{ c->start_embed ()->serialize (c, src, it, layout_variation_idx_delta_map, new_format); } } diff --git a/libs/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh b/libs/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh index b4c9fc3db..b2d151d44 100644 --- a/libs/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh +++ b/libs/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh @@ -8,7 +8,7 @@ namespace OT { namespace Layout { namespace GPOS_impl { -struct SinglePosFormat1 +struct SinglePosFormat1 : ValueBase { protected: HBUINT16 format; /* Format identifier--format = 1 */ @@ -28,7 +28,16 @@ struct SinglePosFormat1 TRACE_SANITIZE (this); return_trace (c->check_struct (this) && coverage.sanitize (c, this) && + hb_barrier () && + /* The coverage table may use a range to represent a set + * of glyphs, which means a small number of bytes can + * generate a large glyph set. Manually modify the + * sanitizer max ops to take this into account. + * + * Note: This check *must* be right after coverage sanitize. */ + c->check_ops ((this + coverage).get_population () >> 1) && valueFormat.sanitize_value (c, this, values)); + } bool intersects (const hb_set_t *glyphs) const @@ -63,7 +72,7 @@ struct SinglePosFormat1 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "positioning glyph at %d", + "positioning glyph at %u", c->buffer->idx); } @@ -72,7 +81,7 @@ struct SinglePosFormat1 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "positioned glyph at %d", + "positioned glyph at %u", c->buffer->idx); } @@ -82,6 +91,7 @@ struct SinglePosFormat1 bool position_single (hb_font_t *font, + hb_blob_t *table_blob, hb_direction_t direction, hb_codepoint_t gid, hb_glyph_position_t &pos) const @@ -92,7 +102,7 @@ struct SinglePosFormat1 /* This is ugly... */ hb_buffer_t buffer; buffer.props.direction = direction; - OT::hb_ot_apply_context_t c (1, font, &buffer); + OT::hb_ot_apply_context_t c (1, font, &buffer, table_blob); valueFormat.apply_value (&c, this, values, pos); return true; @@ -137,6 +147,30 @@ struct SinglePosFormat1 hb_set_t intersection; (this+coverage).intersect_set (glyphset, intersection); + unsigned new_format = valueFormat; + + if (c->plan->normalized_coords) + { + new_format = valueFormat.get_effective_format (values.arrayZ, false, false, this, &c->plan->layout_variation_idx_delta_map); + } + /* do not strip hints for VF */ + else if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING) + { + hb_blob_t* blob = hb_face_reference_table (c->plan->source, HB_TAG ('f','v','a','r')); + bool has_fvar = (blob != hb_blob_get_empty ()); + hb_blob_destroy (blob); + + bool strip = !has_fvar; + /* special case: strip hints when a VF has no GDEF varstore after + * subsetting*/ + if (has_fvar && !c->plan->has_gdef_varstore) + strip = true; + new_format = valueFormat.get_effective_format (values.arrayZ, + strip, /* strip hints */ + true, /* strip empty */ + this, nullptr); + } + auto it = + hb_iter (intersection) | hb_map_retains_sorting (glyph_map) @@ -144,7 +178,7 @@ struct SinglePosFormat1 ; bool ret = bool (it); - SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned); + SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, new_format); return_trace (ret); } }; diff --git a/libs/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh b/libs/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh index c77951156..ae4a5ed75 100644 --- a/libs/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh +++ b/libs/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh @@ -7,7 +7,7 @@ namespace OT { namespace Layout { namespace GPOS_impl { -struct SinglePosFormat2 +struct SinglePosFormat2 : ValueBase { protected: HBUINT16 format; /* Format identifier--format = 2 */ @@ -73,7 +73,7 @@ struct SinglePosFormat2 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "positioning glyph at %d", + "positioning glyph at %u", c->buffer->idx); } @@ -84,7 +84,7 @@ struct SinglePosFormat2 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "positioned glyph at %d", + "positioned glyph at %u", c->buffer->idx); } @@ -94,6 +94,7 @@ struct SinglePosFormat2 bool position_single (hb_font_t *font, + hb_blob_t *table_blob, hb_direction_t direction, hb_codepoint_t gid, hb_glyph_position_t &pos) const @@ -105,7 +106,7 @@ struct SinglePosFormat2 /* This is ugly... */ hb_buffer_t buffer; buffer.props.direction = direction; - OT::hb_ot_apply_context_t c (1, font, &buffer); + OT::hb_ot_apply_context_t c (1, font, &buffer, table_blob); valueFormat.apply_value (&c, this, &values[index * valueFormat.get_len ()], @@ -142,6 +143,37 @@ struct SinglePosFormat2 coverage.serialize_serialize (c, glyphs); } + template + unsigned compute_effective_format (const hb_face_t *face, + Iterator it, + bool is_instancing, bool strip_hints, + bool has_gdef_varstore, + const hb_hashmap_t> *varidx_delta_map) const + { + hb_blob_t* blob = hb_face_reference_table (face, HB_TAG ('f','v','a','r')); + bool has_fvar = (blob != hb_blob_get_empty ()); + hb_blob_destroy (blob); + + unsigned new_format = 0; + if (is_instancing) + { + new_format = new_format | valueFormat.get_effective_format (+ it | hb_map (hb_second), false, false, this, varidx_delta_map); + } + /* do not strip hints for VF */ + else if (strip_hints) + { + bool strip = !has_fvar; + if (has_fvar && !has_gdef_varstore) + strip = true; + new_format = new_format | valueFormat.get_effective_format (+ it | hb_map (hb_second), strip, true, this, nullptr); + } + else + new_format = valueFormat; + + return new_format; + } + bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); @@ -162,8 +194,13 @@ struct SinglePosFormat2 }) ; + unsigned new_format = compute_effective_format (c->plan->source, it, + bool (c->plan->normalized_coords), + bool (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING), + c->plan->has_gdef_varstore, + &c->plan->layout_variation_idx_delta_map); bool ret = bool (it); - SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned); + SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, new_format); return_trace (ret); } }; diff --git a/libs/harfbuzz/src/OT/Layout/GPOS/ValueFormat.hh b/libs/harfbuzz/src/OT/Layout/GPOS/ValueFormat.hh index 26a40f01a..9442cc1cc 100644 --- a/libs/harfbuzz/src/OT/Layout/GPOS/ValueFormat.hh +++ b/libs/harfbuzz/src/OT/Layout/GPOS/ValueFormat.hh @@ -9,6 +9,8 @@ namespace GPOS_impl { typedef HBUINT16 Value; +struct ValueBase {}; // Dummy base class tag for OffsetTo bases. + typedef UnsizedArrayOf ValueRecord; struct ValueFormat : HBUINT16 @@ -78,7 +80,7 @@ struct ValueFormat : HBUINT16 } bool apply_value (hb_ot_apply_context_t *c, - const void *base, + const ValueBase *base, const Value *values, hb_glyph_position_t &glyph_pos) const { @@ -114,35 +116,57 @@ struct ValueFormat : HBUINT16 if (!use_x_device && !use_y_device) return ret; - const VariationStore &store = c->var_store; + const ItemVariationStore &store = c->var_store; auto *cache = c->var_store_cache; /* pixel -> fractional pixel */ - if (format & xPlaDevice) { - if (use_x_device) glyph_pos.x_offset += (base + get_device (values, &ret)).get_x_delta (font, store, cache); + if (format & xPlaDevice) + { + if (use_x_device) glyph_pos.x_offset += get_device (values, &ret, base, c->sanitizer).get_x_delta (font, store, cache); values++; } - if (format & yPlaDevice) { - if (use_y_device) glyph_pos.y_offset += (base + get_device (values, &ret)).get_y_delta (font, store, cache); + if (format & yPlaDevice) + { + if (use_y_device) glyph_pos.y_offset += get_device (values, &ret, base, c->sanitizer).get_y_delta (font, store, cache); values++; } - if (format & xAdvDevice) { - if (horizontal && use_x_device) glyph_pos.x_advance += (base + get_device (values, &ret)).get_x_delta (font, store, cache); + if (format & xAdvDevice) + { + if (horizontal && use_x_device) glyph_pos.x_advance += get_device (values, &ret, base, c->sanitizer).get_x_delta (font, store, cache); values++; } - if (format & yAdvDevice) { + if (format & yAdvDevice) + { /* y_advance values grow downward but font-space grows upward, hence negation */ - if (!horizontal && use_y_device) glyph_pos.y_advance -= (base + get_device (values, &ret)).get_y_delta (font, store, cache); + if (!horizontal && use_y_device) glyph_pos.y_advance -= get_device (values, &ret, base, c->sanitizer).get_y_delta (font, store, cache); values++; } return ret; } - unsigned int get_effective_format (const Value *values) const + unsigned int get_effective_format (const Value *values, bool strip_hints, bool strip_empty, const ValueBase *base, + const hb_hashmap_t> *varidx_delta_map) const { unsigned int format = *this; for (unsigned flag = xPlacement; flag <= yAdvDevice; flag = flag << 1) { - if (format & flag) should_drop (*values++, (Flags) flag, &format); + if (format & flag) + { + if (strip_hints && flag >= xPlaDevice) + { + format = format & ~flag; + values++; + continue; + } + if (varidx_delta_map && flag >= xPlaDevice) + { + update_var_flag (values++, (Flags) flag, &format, base, varidx_delta_map); + continue; + } + /* do not strip empty when instancing, cause we don't know whether the new + * default value is 0 or not */ + if (strip_empty) should_drop (*values, (Flags) flag, &format); + values++; + } } return format; @@ -150,18 +174,19 @@ struct ValueFormat : HBUINT16 template - unsigned int get_effective_format (Iterator it) const { + unsigned int get_effective_format (Iterator it, bool strip_hints, bool strip_empty, const ValueBase *base, + const hb_hashmap_t> *varidx_delta_map) const { unsigned int new_format = 0; for (const hb_array_t& values : it) - new_format = new_format | get_effective_format (&values); + new_format = new_format | get_effective_format (&values, strip_hints, strip_empty, base, varidx_delta_map); return new_format; } void copy_values (hb_serialize_context_t *c, unsigned int new_format, - const void *base, + const ValueBase *base, const Value *values, const hb_hashmap_t> *layout_variation_idx_delta_map) const { @@ -174,6 +199,9 @@ struct ValueFormat : HBUINT16 if (format & xAdvance) x_adv = copy_value (c, new_format, xAdvance, *values++); if (format & yAdvance) y_adv = copy_value (c, new_format, yAdvance, *values++); + if (!has_device ()) + return; + if (format & xPlaDevice) { add_delta_to_value (x_placement, base, values, layout_variation_idx_delta_map); @@ -210,7 +238,7 @@ struct ValueFormat : HBUINT16 } void collect_variation_indices (hb_collect_variation_indices_context_t *c, - const void *base, + const ValueBase *base, const hb_array_t& values) const { unsigned format = *this; @@ -233,30 +261,19 @@ struct ValueFormat : HBUINT16 if (format & ValueFormat::xAdvDevice) { - (base + get_device (&(values[i]))).collect_variation_indices (c); i++; } if (format & ValueFormat::yAdvDevice) { - (base + get_device (&(values[i]))).collect_variation_indices (c); i++; } } - unsigned drop_device_table_flags () const - { - unsigned format = *this; - for (unsigned flag = xPlaDevice; flag <= yAdvDevice; flag = flag << 1) - format = format & ~flag; - - return format; - } - private: - bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const + bool sanitize_value_devices (hb_sanitize_context_t *c, const ValueBase *base, const Value *values) const { unsigned int format = *this; @@ -273,18 +290,31 @@ struct ValueFormat : HBUINT16 return true; } - static inline Offset16To& get_device (Value* value) + static inline Offset16To& get_device (Value* value) { - return *static_cast *> (value); + return *static_cast *> (value); } - static inline const Offset16To& get_device (const Value* value, bool *worked=nullptr) + static inline const Offset16To& get_device (const Value* value) + { + return *static_cast *> (value); + } + static inline const Device& get_device (const Value* value, + bool *worked, + const ValueBase *base, + hb_sanitize_context_t &c) { if (worked) *worked |= bool (*value); - return *static_cast *> (value); + auto &offset = *static_cast *> (value); + + if (unlikely (!offset.sanitize (&c, base))) + return Null(Device); + hb_barrier (); + + return base + offset; } void add_delta_to_value (HBINT16 *value, - const void *base, + const ValueBase *base, const Value *src_value, const hb_hashmap_t> *layout_variation_idx_delta_map) const { @@ -296,7 +326,8 @@ struct ValueFormat : HBUINT16 *value += hb_second (*varidx_delta); } - bool copy_device (hb_serialize_context_t *c, const void *base, + bool copy_device (hb_serialize_context_t *c, + const ValueBase *base, const Value *src_value, const hb_hashmap_t> *layout_variation_idx_delta_map, unsigned int new_format, Flags flag) const @@ -337,32 +368,34 @@ struct ValueFormat : HBUINT16 return (format & devices) != 0; } - bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const + bool sanitize_value (hb_sanitize_context_t *c, const ValueBase *base, const Value *values) const { TRACE_SANITIZE (this); - return_trace (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values))); + + if (unlikely (!c->check_range (values, get_size ()))) return_trace (false); + + if (c->lazy_some_gpos) + return_trace (true); + + return_trace (!has_device () || sanitize_value_devices (c, base, values)); } - bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const + bool sanitize_values (hb_sanitize_context_t *c, const ValueBase *base, const Value *values, unsigned int count) const { TRACE_SANITIZE (this); - unsigned int len = get_len (); - - if (!c->check_range (values, count, get_size ())) return_trace (false); + unsigned size = get_size (); - if (!has_device ()) return_trace (true); + if (!c->check_range (values, count, size)) return_trace (false); - for (unsigned int i = 0; i < count; i++) { - if (!sanitize_value_devices (c, base, values)) - return_trace (false); - values += len; - } + if (c->lazy_some_gpos) + return_trace (true); - return_trace (true); + hb_barrier (); + return_trace (sanitize_values_stride_unsafe (c, base, values, count, size)); } /* Just sanitize referenced Device tables. Doesn't check the values themselves. */ - bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const + bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const ValueBase *base, const Value *values, unsigned int count, unsigned int stride) const { TRACE_SANITIZE (this); @@ -371,7 +404,7 @@ struct ValueFormat : HBUINT16 for (unsigned int i = 0; i < count; i++) { if (!sanitize_value_devices (c, base, values)) return_trace (false); - values += stride; + values = &StructAtOffset (values, stride); } return_trace (true); @@ -385,6 +418,20 @@ struct ValueFormat : HBUINT16 *format = *format & ~flag; } + void update_var_flag (const Value* value, Flags flag, + unsigned int* format, const ValueBase *base, + const hb_hashmap_t> *varidx_delta_map) const + { + if (*value) + { + unsigned varidx = (base + get_device (value)).get_variation_index (); + hb_pair_t *varidx_delta; + if (varidx_delta_map->has (varidx, &varidx_delta) && + varidx_delta->first != HB_OT_LAYOUT_NO_VARIATIONS_INDEX) + return; + } + *format = *format & ~flag; + } }; } diff --git a/libs/harfbuzz/src/OT/Layout/GSUB/AlternateSet.hh b/libs/harfbuzz/src/OT/Layout/GSUB/AlternateSet.hh index 4a9e9672e..b4466119b 100644 --- a/libs/harfbuzz/src/OT/Layout/GSUB/AlternateSet.hh +++ b/libs/harfbuzz/src/OT/Layout/GSUB/AlternateSet.hh @@ -61,7 +61,7 @@ struct AlternateSet { c->buffer->sync_so_far (); c->buffer->message (c->font, - "replacing glyph at %d (alternate substitution)", + "replacing glyph at %u (alternate substitution)", c->buffer->idx); } @@ -70,8 +70,8 @@ struct AlternateSet if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "replaced glyph at %d (alternate substitution)", - c->buffer->idx - 1); + "replaced glyph at %u (alternate substitution)", + c->buffer->idx - 1u); } return_trace (true); @@ -84,7 +84,7 @@ struct AlternateSet { if (alternates.len && alternate_count) { - + alternates.sub_array (start_offset, alternate_count) + + alternates.as_array ().sub_array (start_offset, alternate_count) | hb_sink (hb_array (alternate_glyphs, *alternate_count)) ; } diff --git a/libs/harfbuzz/src/OT/Layout/GSUB/AlternateSubst.hh b/libs/harfbuzz/src/OT/Layout/GSUB/AlternateSubst.hh index 37406179a..04a052a78 100644 --- a/libs/harfbuzz/src/OT/Layout/GSUB/AlternateSubst.hh +++ b/libs/harfbuzz/src/OT/Layout/GSUB/AlternateSubst.hh @@ -14,7 +14,7 @@ struct AlternateSubst union { HBUINT16 format; /* Format identifier */ AlternateSubstFormat1_2 format1; -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K AlternateSubstFormat1_2 format2; #endif } u; @@ -23,11 +23,11 @@ struct AlternateSubst template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); #endif default:return_trace (c->default_return_value ()); diff --git a/libs/harfbuzz/src/OT/Layout/GSUB/Common.hh b/libs/harfbuzz/src/OT/Layout/GSUB/Common.hh index 968bba048..b849494d8 100644 --- a/libs/harfbuzz/src/OT/Layout/GSUB/Common.hh +++ b/libs/harfbuzz/src/OT/Layout/GSUB/Common.hh @@ -8,8 +8,6 @@ namespace OT { namespace Layout { namespace GSUB_impl { -typedef hb_pair_t hb_codepoint_pair_t; - template static void SingleSubst_serialize (hb_serialize_context_t *c, Iterator it); diff --git a/libs/harfbuzz/src/OT/Layout/GSUB/Ligature.hh b/libs/harfbuzz/src/OT/Layout/GSUB/Ligature.hh index 6caa80e05..e0ec82a23 100644 --- a/libs/harfbuzz/src/OT/Layout/GSUB/Ligature.hh +++ b/libs/harfbuzz/src/OT/Layout/GSUB/Ligature.hh @@ -10,10 +10,10 @@ namespace GSUB_impl { template struct Ligature { - protected: + public: typename Types::HBGlyphID ligGlyph; /* GlyphID of ligature to substitute */ - HeadlessArrayOf + HeadlessArray16Of component; /* Array of component GlyphIDs--start * with the second component--ordered * in writing direction */ @@ -29,6 +29,9 @@ struct Ligature bool intersects (const hb_set_t *glyphs) const { return hb_all (component, glyphs); } + bool intersects_lig_glyph (const hb_set_t *glyphs) const + { return glyphs->has(ligGlyph); } + void closure (hb_closure_context_t *c) const { if (!intersects (c->glyphs)) return; @@ -69,7 +72,7 @@ struct Ligature { c->buffer->sync_so_far (); c->buffer->message (c->font, - "replacing glyph at %d (ligature substitution)", + "replacing glyph at %u (ligature substitution)", c->buffer->idx); } @@ -78,8 +81,8 @@ struct Ligature if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "replaced glyph at %d (ligature substitution)", - c->buffer->idx - 1); + "replaced glyph at %u (ligature substitution)", + c->buffer->idx - 1u); } return_trace (true); @@ -87,8 +90,17 @@ struct Ligature unsigned int total_component_count = 0; + if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return false; + unsigned match_positions_stack[4]; + unsigned *match_positions = match_positions_stack; + if (unlikely (count > ARRAY_LENGTH (match_positions_stack))) + { + match_positions = (unsigned *) hb_malloc (hb_max (count, 1u) * sizeof (unsigned)); + if (unlikely (!match_positions)) + return_trace (false); + } + unsigned int match_end = 0; - unsigned int match_positions[HB_MAX_CONTEXT_LENGTH]; if (likely (!match_input (c, count, &component[1], @@ -99,6 +111,8 @@ struct Ligature &total_component_count))) { c->buffer->unsafe_to_concat (c->buffer->idx, match_end); + if (match_positions != match_positions_stack) + hb_free (match_positions); return_trace (false); } @@ -118,7 +132,7 @@ struct Ligature match_positions[i] += delta; if (i) *p++ = ','; - snprintf (p, sizeof(buf), "%u", match_positions[i]); + snprintf (p, sizeof(buf) - (p - buf), "%u", match_positions[i]); p += strlen(p); } @@ -138,10 +152,12 @@ struct Ligature { c->buffer->sync_so_far (); c->buffer->message (c->font, - "ligated glyph at %d", + "ligated glyph at %u", pos); } + if (match_positions != match_positions_stack) + hb_free (match_positions); return_trace (true); } diff --git a/libs/harfbuzz/src/OT/Layout/GSUB/LigatureSet.hh b/libs/harfbuzz/src/OT/Layout/GSUB/LigatureSet.hh index 637cec713..08665438c 100644 --- a/libs/harfbuzz/src/OT/Layout/GSUB/LigatureSet.hh +++ b/libs/harfbuzz/src/OT/Layout/GSUB/LigatureSet.hh @@ -34,6 +34,18 @@ struct LigatureSet ; } + bool intersects_lig_glyph (const hb_set_t *glyphs) const + { + return + + hb_iter (ligature) + | hb_map (hb_add (this)) + | hb_map ([glyphs] (const Ligature &_) { + return _.intersects_lig_glyph (glyphs) && _.intersects (glyphs); + }) + | hb_any + ; + } + void closure (hb_closure_context_t *c) const { + hb_iter (ligature) @@ -63,12 +75,69 @@ struct LigatureSet bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); + unsigned int num_ligs = ligature.len; + +#ifndef HB_NO_OT_RULESETS_FAST_PATH + if (HB_OPTIMIZE_SIZE_VAL || num_ligs <= 4) +#endif + { + slow: + for (unsigned int i = 0; i < num_ligs; i++) + { + const auto &lig = this+ligature.arrayZ[i]; + if (lig.apply (c)) return_trace (true); + } + return_trace (false); + } + + /* This version is optimized for speed by matching the first component + * of the ligature here, instead of calling into the ligation code. + * + * This is replicated in ChainRuleSet and RuleSet. */ + + hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; + skippy_iter.reset (c->buffer->idx); + skippy_iter.set_match_func (match_always, nullptr); + skippy_iter.set_glyph_data ((HBUINT16 *) nullptr); + unsigned unsafe_to; + hb_codepoint_t first = (unsigned) -1; + bool matched = skippy_iter.next (&unsafe_to); + if (likely (matched)) + { + first = c->buffer->info[skippy_iter.idx].codepoint; + unsafe_to = skippy_iter.idx + 1; + + if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx])) + { + /* Can't use the fast path if eg. the next char is a default-ignorable + * or other skippable. */ + goto slow; + } + } + else + goto slow; + + bool unsafe_to_concat = false; + for (unsigned int i = 0; i < num_ligs; i++) { - const auto &lig = this+ligature[i]; - if (lig.apply (c)) return_trace (true); + const auto &lig = this+ligature.arrayZ[i]; + if (unlikely (lig.component.lenP1 <= 1) || + lig.component.arrayZ[0] == first) + { + if (lig.apply (c)) + { + if (unsafe_to_concat) + c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to); + return_trace (true); + } + } + else if (likely (lig.component.lenP1 > 1)) + unsafe_to_concat = true; } + if (likely (unsafe_to_concat)) + c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to); return_trace (false); } diff --git a/libs/harfbuzz/src/OT/Layout/GSUB/LigatureSubst.hh b/libs/harfbuzz/src/OT/Layout/GSUB/LigatureSubst.hh index 63707972a..18f6e3558 100644 --- a/libs/harfbuzz/src/OT/Layout/GSUB/LigatureSubst.hh +++ b/libs/harfbuzz/src/OT/Layout/GSUB/LigatureSubst.hh @@ -14,7 +14,7 @@ struct LigatureSubst union { HBUINT16 format; /* Format identifier */ LigatureSubstFormat1_2 format1; -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K LigatureSubstFormat1_2 format2; #endif } u; @@ -23,11 +23,11 @@ struct LigatureSubst template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); #endif default:return_trace (c->default_return_value ()); diff --git a/libs/harfbuzz/src/OT/Layout/GSUB/LigatureSubstFormat1.hh b/libs/harfbuzz/src/OT/Layout/GSUB/LigatureSubstFormat1.hh index 32b642c38..5c7df97d1 100644 --- a/libs/harfbuzz/src/OT/Layout/GSUB/LigatureSubstFormat1.hh +++ b/libs/harfbuzz/src/OT/Layout/GSUB/LigatureSubstFormat1.hh @@ -130,7 +130,7 @@ struct LigatureSubstFormat1_2 + hb_zip (this+coverage, hb_iter (ligatureSet) | hb_map (hb_add (this))) | hb_filter (glyphset, hb_first) | hb_filter ([&] (const LigatureSet& _) { - return _.intersects (&glyphset); + return _.intersects_lig_glyph (&glyphset); }, hb_second) | hb_map (hb_first) | hb_sink (new_coverage); diff --git a/libs/harfbuzz/src/OT/Layout/GSUB/MultipleSubst.hh b/libs/harfbuzz/src/OT/Layout/GSUB/MultipleSubst.hh index 852ca3eac..742c8587e 100644 --- a/libs/harfbuzz/src/OT/Layout/GSUB/MultipleSubst.hh +++ b/libs/harfbuzz/src/OT/Layout/GSUB/MultipleSubst.hh @@ -14,7 +14,7 @@ struct MultipleSubst union { HBUINT16 format; /* Format identifier */ MultipleSubstFormat1_2 format1; -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K MultipleSubstFormat1_2 format2; #endif } u; @@ -24,11 +24,11 @@ struct MultipleSubst template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); #endif default:return_trace (c->default_return_value ()); diff --git a/libs/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubst.hh b/libs/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubst.hh index 48e208efb..5ad463fea 100644 --- a/libs/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubst.hh +++ b/libs/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubst.hh @@ -20,8 +20,8 @@ struct ReverseChainSingleSubst template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); default:return_trace (c->default_return_value ()); diff --git a/libs/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh b/libs/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh index a23e92028..ec374f2f0 100644 --- a/libs/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh +++ b/libs/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh @@ -33,9 +33,11 @@ struct ReverseChainSingleSubstFormat1 TRACE_SANITIZE (this); if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this))) return_trace (false); + hb_barrier (); const auto &lookahead = StructAfter (backtrack); if (!lookahead.sanitize (c, this)) return_trace (false); + hb_barrier (); const auto &substitute = StructAfter (lookahead); return_trace (substitute.sanitize (c)); } @@ -109,12 +111,12 @@ struct ReverseChainSingleSubstFormat1 bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); - if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL)) - return_trace (false); /* No chaining to this type */ - unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint); if (likely (index == NOT_COVERED)) return_trace (false); + if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL)) + return_trace (false); /* No chaining to this type */ + const auto &lookahead = StructAfter (backtrack); const auto &substitute = StructAfter (lookahead); @@ -135,7 +137,7 @@ struct ReverseChainSingleSubstFormat1 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "replacing glyph at %d (reverse chaining substitution)", + "replacing glyph at %u (reverse chaining substitution)", c->buffer->idx); } @@ -144,7 +146,7 @@ struct ReverseChainSingleSubstFormat1 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "replaced glyph at %d (reverse chaining substitution)", + "replaced glyph at %u (reverse chaining substitution)", c->buffer->idx); } @@ -191,7 +193,6 @@ struct ReverseChainSingleSubstFormat1 TRACE_SERIALIZE (this); auto *out = c->serializer->start_embed (this); - if (unlikely (!c->serializer->check_success (out))) return_trace (false); if (unlikely (!c->serializer->embed (this->format))) return_trace (false); if (unlikely (!c->serializer->embed (this->coverage))) return_trace (false); diff --git a/libs/harfbuzz/src/OT/Layout/GSUB/Sequence.hh b/libs/harfbuzz/src/OT/Layout/GSUB/Sequence.hh index abf1c643f..a26cf8c6a 100644 --- a/libs/harfbuzz/src/OT/Layout/GSUB/Sequence.hh +++ b/libs/harfbuzz/src/OT/Layout/GSUB/Sequence.hh @@ -44,7 +44,7 @@ struct Sequence { c->buffer->sync_so_far (); c->buffer->message (c->font, - "replacing glyph at %d (multiple substitution)", + "replacing glyph at %u (multiple substitution)", c->buffer->idx); } @@ -53,8 +53,8 @@ struct Sequence if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "replaced glyph at %d (multiple subtitution)", - c->buffer->idx - 1); + "replaced glyph at %u (multiple substitution)", + c->buffer->idx - 1u); } return_trace (true); @@ -67,7 +67,7 @@ struct Sequence { c->buffer->sync_so_far (); c->buffer->message (c->font, - "deleting glyph at %d (multiple substitution)", + "deleting glyph at %u (multiple substitution)", c->buffer->idx); } @@ -77,7 +77,7 @@ struct Sequence { c->buffer->sync_so_far (); c->buffer->message (c->font, - "deleted glyph at %d (multiple substitution)", + "deleted glyph at %u (multiple substitution)", c->buffer->idx); } @@ -88,7 +88,7 @@ struct Sequence { c->buffer->sync_so_far (); c->buffer->message (c->font, - "multiplying glyph at %d", + "multiplying glyph at %u", c->buffer->idx); } @@ -117,7 +117,7 @@ struct Sequence { if (buf < p) *p++ = ','; - snprintf (p, sizeof(buf), "%u", i); + snprintf (p, sizeof(buf) - (p - buf), "%u", i); p += strlen(p); } diff --git a/libs/harfbuzz/src/OT/Layout/GSUB/SingleSubst.hh b/libs/harfbuzz/src/OT/Layout/GSUB/SingleSubst.hh index 6942e6997..181c9e52e 100644 --- a/libs/harfbuzz/src/OT/Layout/GSUB/SingleSubst.hh +++ b/libs/harfbuzz/src/OT/Layout/GSUB/SingleSubst.hh @@ -16,7 +16,7 @@ struct SingleSubst HBUINT16 format; /* Format identifier */ SingleSubstFormat1_3 format1; SingleSubstFormat2_4 format2; -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K SingleSubstFormat1_3 format3; SingleSubstFormat2_4 format4; #endif @@ -27,12 +27,12 @@ struct SingleSubst template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K case 3: return_trace (c->dispatch (u.format3, std::forward (ds)...)); case 4: return_trace (c->dispatch (u.format4, std::forward (ds)...)); #endif @@ -55,9 +55,9 @@ struct SingleSubst format = 1; hb_codepoint_t mask = 0xFFFFu; -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K if (+ glyphs - | hb_map_retains_sorting (hb_first) + | hb_map_retains_sorting (hb_second) | hb_filter ([] (hb_codepoint_t gid) { return gid > 0xFFFFu; })) { format += 2; @@ -78,7 +78,7 @@ struct SingleSubst | hb_map_retains_sorting (hb_first), delta)); case 2: return_trace (u.format2.serialize (c, glyphs)); -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K case 3: return_trace (u.format3.serialize (c, + glyphs | hb_map_retains_sorting (hb_first), diff --git a/libs/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh b/libs/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh index 13665d7ba..850be86c0 100644 --- a/libs/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh +++ b/libs/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh @@ -25,7 +25,15 @@ struct SingleSubstFormat1_3 bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c)); + return_trace (c->check_struct (this) && + coverage.sanitize (c, this) && + /* The coverage table may use a range to represent a set + * of glyphs, which means a small number of bytes can + * generate a large glyph set. Manually modify the + * sanitizer max ops to take this into account. + * + * Note: This check *must* be right after coverage sanitize. */ + c->check_ops ((this + coverage).get_population () >> 1)); } hb_codepoint_t get_mask () const @@ -57,7 +65,7 @@ struct SingleSubstFormat1_3 hb_codepoint_t max_before = intersection.get_max (); hb_codepoint_t min_after = (min_before + d) & mask; hb_codepoint_t max_after = (max_before + d) & mask; - if (pop >= max_before - min_before && + if (intersection.get_population () == max_before - min_before + 1 && ((min_before <= min_after && min_after <= max_before) || (min_before <= max_after && max_after <= max_before))) return; @@ -87,6 +95,34 @@ struct SingleSubstFormat1_3 bool would_apply (hb_would_apply_context_t *c) const { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; } + unsigned + get_glyph_alternates (hb_codepoint_t glyph_id, + unsigned start_offset, + unsigned *alternate_count /* IN/OUT. May be NULL. */, + hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) const + { + unsigned int index = (this+coverage).get_coverage (glyph_id); + if (likely (index == NOT_COVERED)) + { + if (alternate_count) + *alternate_count = 0; + return 0; + } + + if (alternate_count && *alternate_count) + { + hb_codepoint_t d = deltaGlyphID; + hb_codepoint_t mask = get_mask (); + + glyph_id = (glyph_id + d) & mask; + + *alternate_glyphs = glyph_id; + *alternate_count = 1; + } + + return 1; + } + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); @@ -103,7 +139,7 @@ struct SingleSubstFormat1_3 { c->buffer->sync_so_far (); c->buffer->message (c->font, - "replacing glyph at %d (single substitution)", + "replacing glyph at %u (single substitution)", c->buffer->idx); } @@ -112,8 +148,8 @@ struct SingleSubstFormat1_3 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "replaced glyph at %d (single substitution)", - c->buffer->idx - 1); + "replaced glyph at %u (single substitution)", + c->buffer->idx - 1u); } return_trace (true); diff --git a/libs/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh b/libs/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh index 541629975..9c651abe7 100644 --- a/libs/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh +++ b/libs/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh @@ -36,8 +36,24 @@ struct SingleSubstFormat2_4 void closure (hb_closure_context_t *c) const { - + hb_zip (this+coverage, substitute) - | hb_filter (c->parent_active_glyphs (), hb_first) + auto &cov = this+coverage; + auto &glyph_set = c->parent_active_glyphs (); + + if (substitute.len > glyph_set.get_population () * 4) + { + for (auto g : glyph_set) + { + unsigned i = cov.get_coverage (g); + if (i == NOT_COVERED || i >= substitute.len) + continue; + c->output->add (substitute.arrayZ[i]); + } + + return; + } + + + hb_zip (cov, substitute) + | hb_filter (glyph_set, hb_first) | hb_map (hb_second) | hb_sink (c->output) ; @@ -59,6 +75,31 @@ struct SingleSubstFormat2_4 bool would_apply (hb_would_apply_context_t *c) const { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; } + unsigned + get_glyph_alternates (hb_codepoint_t glyph_id, + unsigned start_offset, + unsigned *alternate_count /* IN/OUT. May be NULL. */, + hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) const + { + unsigned int index = (this+coverage).get_coverage (glyph_id); + if (likely (index == NOT_COVERED)) + { + if (alternate_count) + *alternate_count = 0; + return 0; + } + + if (alternate_count && *alternate_count) + { + glyph_id = substitute[index]; + + *alternate_glyphs = glyph_id; + *alternate_count = 1; + } + + return 1; + } + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); @@ -71,7 +112,7 @@ struct SingleSubstFormat2_4 { c->buffer->sync_so_far (); c->buffer->message (c->font, - "replacing glyph at %d (single substitution)", + "replacing glyph at %u (single substitution)", c->buffer->idx); } @@ -80,8 +121,8 @@ struct SingleSubstFormat2_4 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "replaced glyph at %d (single substitution)", - c->buffer->idx - 1); + "replaced glyph at %u (single substitution)", + c->buffer->idx - 1u); } return_trace (true); diff --git a/libs/harfbuzz/src/OT/Layout/types.hh b/libs/harfbuzz/src/OT/Layout/types.hh index 6a43403e9..3840db059 100644 --- a/libs/harfbuzz/src/OT/Layout/types.hh +++ b/libs/harfbuzz/src/OT/Layout/types.hh @@ -38,8 +38,8 @@ struct SmallTypes { using HBUINT = HBUINT16; using HBGlyphID = HBGlyphID16; using Offset = Offset16; - template - using OffsetTo = OT::Offset16To; + template + using OffsetTo = OT::Offset16To; template using ArrayOf = OT::Array16Of; template @@ -52,8 +52,8 @@ struct MediumTypes { using HBUINT = HBUINT24; using HBGlyphID = HBGlyphID24; using Offset = Offset24; - template - using OffsetTo = OT::Offset24To; + template + using OffsetTo = OT::Offset24To; template using ArrayOf = OT::Array24Of; template diff --git a/libs/harfbuzz/src/OT/Var/VARC/VARC.cc b/libs/harfbuzz/src/OT/Var/VARC/VARC.cc new file mode 100644 index 000000000..1afb57111 --- /dev/null +++ b/libs/harfbuzz/src/OT/Var/VARC/VARC.cc @@ -0,0 +1,346 @@ +#include "VARC.hh" + +#ifndef HB_NO_VAR_COMPOSITES + +#include "../../../hb-draw.hh" +#include "../../../hb-geometry.hh" +#include "../../../hb-ot-layout-common.hh" +#include "../../../hb-ot-layout-gdef-table.hh" + +namespace OT { + +//namespace Var { + + +struct hb_transforming_pen_context_t +{ + hb_transform_t transform; + hb_draw_funcs_t *dfuncs; + void *data; + hb_draw_state_t *st; +}; + +static void +hb_transforming_pen_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED, + void *data, + hb_draw_state_t *st, + float to_x, float to_y, + void *user_data HB_UNUSED) +{ + hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data; + + c->transform.transform_point (to_x, to_y); + + c->dfuncs->move_to (c->data, *c->st, to_x, to_y); +} + +static void +hb_transforming_pen_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED, + void *data, + hb_draw_state_t *st, + float to_x, float to_y, + void *user_data HB_UNUSED) +{ + hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data; + + c->transform.transform_point (to_x, to_y); + + c->dfuncs->line_to (c->data, *c->st, to_x, to_y); +} + +static void +hb_transforming_pen_quadratic_to (hb_draw_funcs_t *dfuncs HB_UNUSED, + void *data, + hb_draw_state_t *st, + float control_x, float control_y, + float to_x, float to_y, + void *user_data HB_UNUSED) +{ + hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data; + + c->transform.transform_point (control_x, control_y); + c->transform.transform_point (to_x, to_y); + + c->dfuncs->quadratic_to (c->data, *c->st, control_x, control_y, to_x, to_y); +} + +static void +hb_transforming_pen_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED, + void *data, + hb_draw_state_t *st, + float control1_x, float control1_y, + float control2_x, float control2_y, + float to_x, float to_y, + void *user_data HB_UNUSED) +{ + hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data; + + c->transform.transform_point (control1_x, control1_y); + c->transform.transform_point (control2_x, control2_y); + c->transform.transform_point (to_x, to_y); + + c->dfuncs->cubic_to (c->data, *c->st, control1_x, control1_y, control2_x, control2_y, to_x, to_y); +} + +static void +hb_transforming_pen_close_path (hb_draw_funcs_t *dfuncs HB_UNUSED, + void *data, + hb_draw_state_t *st, + void *user_data HB_UNUSED) +{ + hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data; + + c->dfuncs->close_path (c->data, *c->st); +} + +static inline void free_static_transforming_pen_funcs (); + +static struct hb_transforming_pen_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t +{ + static hb_draw_funcs_t *create () + { + hb_draw_funcs_t *funcs = hb_draw_funcs_create (); + + hb_draw_funcs_set_move_to_func (funcs, hb_transforming_pen_move_to, nullptr, nullptr); + hb_draw_funcs_set_line_to_func (funcs, hb_transforming_pen_line_to, nullptr, nullptr); + hb_draw_funcs_set_quadratic_to_func (funcs, hb_transforming_pen_quadratic_to, nullptr, nullptr); + hb_draw_funcs_set_cubic_to_func (funcs, hb_transforming_pen_cubic_to, nullptr, nullptr); + hb_draw_funcs_set_close_path_func (funcs, hb_transforming_pen_close_path, nullptr, nullptr); + + hb_draw_funcs_make_immutable (funcs); + + hb_atexit (free_static_transforming_pen_funcs); + + return funcs; + } +} static_transforming_pen_funcs; + +static inline +void free_static_transforming_pen_funcs () +{ + static_transforming_pen_funcs.free_instance (); +} + +static hb_draw_funcs_t * +hb_transforming_pen_get_funcs () +{ + return static_transforming_pen_funcs.get_unconst (); +} + + +hb_ubytes_t +VarComponent::get_path_at (hb_font_t *font, + hb_codepoint_t parent_gid, + hb_draw_session_t &draw_session, + hb_array_t coords, + hb_ubytes_t total_record, + hb_set_t *visited, + signed *edges_left, + signed depth_left, + VarRegionList::cache_t *cache) const +{ + const unsigned char *end = total_record.arrayZ + total_record.length; + const unsigned char *record = total_record.arrayZ; + + auto &VARC = *font->face->table.VARC; + auto &varStore = &VARC+VARC.varStore; + auto instancer = MultiItemVarStoreInstancer(&varStore, nullptr, coords, cache); + +#define READ_UINT32VAR(name) \ + HB_STMT_START { \ + if (unlikely (unsigned (end - record) < HBUINT32VAR::min_size)) return hb_ubytes_t (); \ + hb_barrier (); \ + auto &varint = * (const HBUINT32VAR *) record; \ + unsigned size = varint.get_size (); \ + if (unlikely (unsigned (end - record) < size)) return hb_ubytes_t (); \ + name = (uint32_t) varint; \ + record += size; \ + } HB_STMT_END + + uint32_t flags; + READ_UINT32VAR (flags); + + // gid + + hb_codepoint_t gid = 0; + if (flags & (unsigned) flags_t::GID_IS_24BIT) + { + if (unlikely (unsigned (end - record) < HBGlyphID24::static_size)) + return hb_ubytes_t (); + hb_barrier (); + gid = * (const HBGlyphID24 *) record; + record += HBGlyphID24::static_size; + } + else + { + if (unlikely (unsigned (end - record) < HBGlyphID16::static_size)) + return hb_ubytes_t (); + hb_barrier (); + gid = * (const HBGlyphID16 *) record; + record += HBGlyphID16::static_size; + } + + // Condition + bool show = true; + if (flags & (unsigned) flags_t::HAVE_CONDITION) + { + unsigned conditionIndex; + READ_UINT32VAR (conditionIndex); + const auto &condition = (&VARC+VARC.conditionList)[conditionIndex]; + show = condition.evaluate (coords.arrayZ, coords.length, &instancer); + } + + // Axis values + + hb_vector_t axisIndices; + hb_vector_t axisValues; + if (flags & (unsigned) flags_t::HAVE_AXES) + { + unsigned axisIndicesIndex; + READ_UINT32VAR (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; + } + + // Apply variations if any + if (flags & (unsigned) flags_t::AXIS_VALUES_HAVE_VARIATION) + { + uint32_t axisValuesVarIdx; + READ_UINT32VAR (axisValuesVarIdx); + if (show && coords && !axisValues.in_error ()) + varStore.get_delta (axisValuesVarIdx, coords, axisValues.as_array (), cache); + } + + auto component_coords = coords; + /* Copying coords is expensive; so we have put an arbitrary + * 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 (font->coords, font->num_coords); + + // Transform + + uint32_t transformVarIdx = VarIdx::NO_VARIATION; + if (flags & (unsigned) flags_t::TRANSFORM_HAS_VARIATION) + READ_UINT32VAR (transformVarIdx); + +#define PROCESS_TRANSFORM_COMPONENTS \ + HB_STMT_START { \ + PROCESS_TRANSFORM_COMPONENT (FWORD, HAVE_TRANSLATE_X, translateX); \ + PROCESS_TRANSFORM_COMPONENT (FWORD, HAVE_TRANSLATE_Y, translateY); \ + PROCESS_TRANSFORM_COMPONENT (F4DOT12, HAVE_ROTATION, rotation); \ + PROCESS_TRANSFORM_COMPONENT (F6DOT10, HAVE_SCALE_X, scaleX); \ + PROCESS_TRANSFORM_COMPONENT (F6DOT10, HAVE_SCALE_Y, scaleY); \ + PROCESS_TRANSFORM_COMPONENT (F4DOT12, HAVE_SKEW_X, skewX); \ + PROCESS_TRANSFORM_COMPONENT (F4DOT12, HAVE_SKEW_Y, skewY); \ + PROCESS_TRANSFORM_COMPONENT (FWORD, HAVE_TCENTER_X, tCenterX); \ + PROCESS_TRANSFORM_COMPONENT (FWORD, HAVE_TCENTER_Y, tCenterY); \ + } HB_STMT_END + + hb_transform_decomposed_t transform; + + // Read transform components +#define PROCESS_TRANSFORM_COMPONENT(type, flag, name) \ + if (flags & (unsigned) flags_t::flag) \ + { \ + static_assert (type::static_size == HBINT16::static_size, ""); \ + if (unlikely (unsigned (end - record) < HBINT16::static_size)) \ + return hb_ubytes_t (); \ + hb_barrier (); \ + transform.name = * (const HBINT16 *) record; \ + record += HBINT16::static_size; \ + } + PROCESS_TRANSFORM_COMPONENTS; +#undef PROCESS_TRANSFORM_COMPONENT + + // Read reserved records + unsigned i = flags & (unsigned) flags_t::RESERVED_MASK; + while (i) + { + HB_UNUSED uint32_t discard; + READ_UINT32VAR (discard); + i &= i - 1; + } + + /* Parsing is over now. */ + + if (show) + { + // Only use coord_setter if there's actually any axis overrides. + coord_setter_t coord_setter (axisIndices ? component_coords : hb_array ()); + // Go backwards, to reduce coord_setter vector reallocations. + for (unsigned i = axisIndices.length; i; i--) + coord_setter[axisIndices[i - 1]] = axisValues[i - 1]; + if (axisIndices) + component_coords = coord_setter.get_coords (); + + // Apply transform variations if any + if (transformVarIdx != VarIdx::NO_VARIATION && coords) + { + float transformValues[9]; + unsigned numTransformValues = 0; +#define PROCESS_TRANSFORM_COMPONENT(type, flag, name) \ + if (flags & (unsigned) flags_t::flag) \ + transformValues[numTransformValues++] = transform.name; + PROCESS_TRANSFORM_COMPONENTS; +#undef PROCESS_TRANSFORM_COMPONENT + varStore.get_delta (transformVarIdx, coords, hb_array (transformValues, numTransformValues), cache); + numTransformValues = 0; +#define PROCESS_TRANSFORM_COMPONENT(type, flag, name) \ + if (flags & (unsigned) flags_t::flag) \ + transform.name = transformValues[numTransformValues++]; + PROCESS_TRANSFORM_COMPONENTS; +#undef PROCESS_TRANSFORM_COMPONENT + } + + // Divide them by their divisors +#define PROCESS_TRANSFORM_COMPONENT(type, flag, name) \ + if (flags & (unsigned) flags_t::flag) \ + { \ + HBINT16 int_v; \ + int_v = roundf (transform.name); \ + type typed_v = * (const type *) &int_v; \ + float float_v = (float) typed_v; \ + transform.name = float_v; \ + } + PROCESS_TRANSFORM_COMPONENTS; +#undef PROCESS_TRANSFORM_COMPONENT + + if (!(flags & (unsigned) flags_t::HAVE_SCALE_Y)) + transform.scaleY = transform.scaleX; + + // Scale the transform by the font's scale + float x_scale = font->x_multf; + float y_scale = font->y_multf; + transform.translateX *= x_scale; + transform.translateY *= y_scale; + transform.tCenterX *= x_scale; + transform.tCenterY *= y_scale; + + // Build a transforming pen to apply the transform. + hb_draw_funcs_t *transformer_funcs = hb_transforming_pen_get_funcs (); + hb_transforming_pen_context_t context {transform.to_transform (), + draw_session.funcs, + draw_session.draw_data, + &draw_session.st}; + hb_draw_session_t transformer_session {transformer_funcs, &context}; + + VARC.get_path_at (font, gid, + transformer_session, component_coords, + parent_gid, + visited, edges_left, depth_left - 1); + } + +#undef PROCESS_TRANSFORM_COMPONENTS +#undef READ_UINT32VAR + + return hb_ubytes_t (record, end - record); +} + +//} // namespace Var +} // namespace OT + +#endif diff --git a/libs/harfbuzz/src/OT/Var/VARC/VARC.hh b/libs/harfbuzz/src/OT/Var/VARC/VARC.hh new file mode 100644 index 000000000..d60f7b0c2 --- /dev/null +++ b/libs/harfbuzz/src/OT/Var/VARC/VARC.hh @@ -0,0 +1,193 @@ +#ifndef OT_VAR_VARC_VARC_HH +#define OT_VAR_VARC_VARC_HH + +#include "../../../hb-ot-layout-common.hh" +#include "../../../hb-ot-glyf-table.hh" +#include "../../../hb-ot-cff2-table.hh" +#include "../../../hb-ot-cff1-table.hh" + +#include "coord-setter.hh" + +namespace OT { + +//namespace Var { + +/* + * VARC -- Variable Composites + * https://github.com/harfbuzz/boring-expansion-spec/blob/main/VARC.md + */ + +#ifndef HB_NO_VAR_COMPOSITES + +struct VarComponent +{ + enum class flags_t : uint32_t + { + RESET_UNSPECIFIED_AXES = 1u << 0, + HAVE_AXES = 1u << 1, + AXIS_VALUES_HAVE_VARIATION = 1u << 2, + TRANSFORM_HAS_VARIATION = 1u << 3, + HAVE_TRANSLATE_X = 1u << 4, + HAVE_TRANSLATE_Y = 1u << 5, + HAVE_ROTATION = 1u << 6, + HAVE_CONDITION = 1u << 7, + HAVE_SCALE_X = 1u << 8, + HAVE_SCALE_Y = 1u << 9, + HAVE_TCENTER_X = 1u << 10, + HAVE_TCENTER_Y = 1u << 11, + GID_IS_24BIT = 1u << 12, + HAVE_SKEW_X = 1u << 13, + HAVE_SKEW_Y = 1u << 14, + RESERVED_MASK = ~((1u << 15) - 1), + }; + + HB_INTERNAL hb_ubytes_t + get_path_at (hb_font_t *font, + hb_codepoint_t parent_gid, + hb_draw_session_t &draw_session, + hb_array_t coords, + hb_ubytes_t record, + hb_set_t *visited, + signed *edges_left, + signed depth_left, + VarRegionList::cache_t *cache = nullptr) const; +}; + +struct VarCompositeGlyph +{ + static void + get_path_at (hb_font_t *font, + hb_codepoint_t glyph, + hb_draw_session_t &draw_session, + hb_array_t coords, + hb_ubytes_t record, + hb_set_t *visited, + signed *edges_left, + signed depth_left, + VarRegionList::cache_t *cache = nullptr) + { + while (record) + { + const VarComponent &comp = * (const VarComponent *) (record.arrayZ); + record = comp.get_path_at (font, glyph, + draw_session, coords, + record, + visited, edges_left, depth_left, cache); + } + } +}; + +HB_MARK_AS_FLAG_T (VarComponent::flags_t); + +struct VARC +{ + friend struct VarComponent; + + static constexpr hb_tag_t tableTag = HB_TAG ('V', 'A', 'R', 'C'); + + bool + get_path_at (hb_font_t *font, + hb_codepoint_t glyph, + hb_draw_session_t &draw_session, + hb_array_t coords, + hb_codepoint_t parent_glyph = HB_CODEPOINT_INVALID, + hb_set_t *visited = nullptr, + signed *edges_left = nullptr, + signed depth_left = HB_MAX_NESTING_LEVEL) const + { + hb_set_t stack_set; + if (visited == nullptr) + visited = &stack_set; + signed stack_edges = HB_MAX_GRAPH_EDGE_COUNT; + if (edges_left == nullptr) + edges_left = &stack_edges; + + // Don't recurse on the same glyph. + unsigned idx = glyph == parent_glyph ? + NOT_COVERED : + (this+coverage).get_coverage (glyph); + if (idx == NOT_COVERED) + { + if (!font->face->table.glyf->get_path_at (font, glyph, draw_session, coords)) +#ifndef HB_NO_CFF + if (!font->face->table.cff2->get_path_at (font, glyph, draw_session, coords)) + if (!font->face->table.cff1->get_path (font, glyph, draw_session)) // Doesn't have variations +#endif + return false; + return true; + } + + if (depth_left <= 0) + return true; + + if (*edges_left <= 0) + return true; + (*edges_left)--; + + if (visited->has (glyph) || visited->in_error ()) + return true; + visited->add (glyph); + + hb_ubytes_t record = (this+glyphRecords)[idx]; + + VarRegionList::cache_t *cache = record.length >= 64 ? // Heuristic + (this+varStore).create_cache () + : nullptr; + + VarCompositeGlyph::get_path_at (font, glyph, + draw_session, coords, + record, + visited, edges_left, depth_left, + cache); + + (this+varStore).destroy_cache (cache); + + visited->del (glyph); + + return true; + } + + bool + get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const + { return get_path_at (font, gid, draw_session, hb_array (font->coords, font->num_coords)); } + + bool paint_glyph (hb_font_t *font, hb_codepoint_t gid, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const + { + funcs->push_clip_glyph (data, gid, font); + funcs->color (data, true, foreground); + funcs->pop_clip (data); + + return true; + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (version.sanitize (c) && + hb_barrier () && + version.major == 1 && + coverage.sanitize (c, this) && + varStore.sanitize (c, this) && + conditionList.sanitize (c, this) && + axisIndicesList.sanitize (c, this) && + glyphRecords.sanitize (c, this)); + } + + protected: + FixedVersion<> version; /* Version identifier */ + Offset32To coverage; + Offset32To varStore; + Offset32To conditionList; + Offset32To axisIndicesList; + Offset32To*/> glyphRecords; + public: + DEFINE_SIZE_STATIC (24); +}; + +#endif + +//} + +} + +#endif /* OT_VAR_VARC_VARC_HH */ diff --git a/libs/harfbuzz/src/OT/Var/VARC/coord-setter.hh b/libs/harfbuzz/src/OT/Var/VARC/coord-setter.hh new file mode 100644 index 000000000..a2b483ce2 --- /dev/null +++ b/libs/harfbuzz/src/OT/Var/VARC/coord-setter.hh @@ -0,0 +1,37 @@ +#ifndef OT_VAR_VARC_COORD_SETTER_HH +#define OT_VAR_VARC_COORD_SETTER_HH + + +#include "../../../hb.hh" + + +namespace OT { +//namespace Var { + + +struct coord_setter_t +{ + coord_setter_t (hb_array_t coords) : + coords (coords) {} + + int& operator [] (unsigned idx) + { + if (unlikely (idx >= HB_VAR_COMPOSITE_MAX_AXES)) + return Crap(int); + if (coords.length < idx + 1) + coords.resize (idx + 1); + return coords[idx]; + } + + hb_array_t get_coords () + { return coords.as_array (); } + + hb_vector_t coords; +}; + + +//} // namespace Var + +} // namespace OT + +#endif /* OT_VAR_VARC_COORD_SETTER_HH */ diff --git a/libs/harfbuzz/src/OT/glyf/CompositeGlyph.hh b/libs/harfbuzz/src/OT/glyf/CompositeGlyph.hh index fc8e309bc..5c0ecd513 100644 --- a/libs/harfbuzz/src/OT/glyf/CompositeGlyph.hh +++ b/libs/harfbuzz/src/OT/glyf/CompositeGlyph.hh @@ -3,6 +3,7 @@ #include "../../hb-open-type.hh" +#include "composite-iter.hh" namespace OT { @@ -86,27 +87,69 @@ struct CompositeGlyphRecord } } - void transform_points (contour_point_vector_t &points) const + static void transform (const float (&matrix)[4], + hb_array_t points) { - float matrix[4]; - contour_point_t trans; - if (get_transformation (matrix, trans)) + if (matrix[0] != 1.f || matrix[1] != 0.f || + matrix[2] != 0.f || matrix[3] != 1.f) + for (auto &point : points) + point.transform (matrix); + } + + static void translate (const contour_point_t &trans, + hb_array_t points) + { + if (HB_OPTIMIZE_SIZE_VAL) { - if (scaled_offsets ()) - { - points.translate (trans); - points.transform (matrix); - } + if (trans.x != 0.f || trans.y != 0.f) + for (auto &point : points) + point.translate (trans); + } + else + { + if (trans.x != 0.f && trans.y != 0.f) + for (auto &point : points) + point.translate (trans); else { - points.transform (matrix); - points.translate (trans); + if (trans.x != 0.f) + for (auto &point : points) + point.x += trans.x; + else if (trans.y != 0.f) + for (auto &point : points) + point.y += trans.y; } } } - unsigned compile_with_deltas (const contour_point_t &p_delta, - char *out) const + void transform_points (hb_array_t points, + const float (&matrix)[4], + const contour_point_t &trans) const + { + if (scaled_offsets ()) + { + translate (trans, points); + transform (matrix, points); + } + else + { + transform (matrix, points); + translate (trans, points); + } + } + + bool get_points (contour_point_vector_t &points) const + { + float matrix[4]; + contour_point_t trans; + get_transformation (matrix, trans); + if (unlikely (!points.alloc (points.length + 4))) return false; // For phantom points + points.push (trans); + return true; + } + + unsigned compile_with_point (const contour_point_t &point, + char *out) const { const HBINT8 *p = &StructAfter (flags); #ifndef HB_NO_BEYOND_64K @@ -120,30 +163,29 @@ struct CompositeGlyphRecord unsigned len_before_val = (const char *)p - (const char *)this; if (flags & ARG_1_AND_2_ARE_WORDS) { - // no overflow, copy and update value with deltas - memcpy (out, this, len); + // no overflow, copy value + hb_memcpy (out, this, len); - const HBINT16 *px = reinterpret_cast (p); HBINT16 *o = reinterpret_cast (out + len_before_val); - o[0] = px[0] + roundf (p_delta.x); - o[1] = px[1] + roundf (p_delta.y); + o[0] = roundf (point.x); + o[1] = roundf (point.y); } else { - int new_x = p[0] + roundf (p_delta.x); - int new_y = p[1] + roundf (p_delta.y); + int new_x = roundf (point.x); + int new_y = roundf (point.y); if (new_x <= 127 && new_x >= -128 && new_y <= 127 && new_y >= -128) { - memcpy (out, this, len); + hb_memcpy (out, this, len); HBINT8 *o = reinterpret_cast (out + len_before_val); o[0] = new_x; o[1] = new_y; } else { - // int8 overflows after deltas applied - memcpy (out, this, len_before_val); + // new point value has an int8 overflow + hb_memcpy (out, this, len_before_val); //update flags CompositeGlyphRecord *o = reinterpret_cast (out); @@ -152,14 +194,14 @@ struct CompositeGlyphRecord HBINT16 new_value; new_value = new_x; - memcpy (out, &new_value, HBINT16::static_size); + hb_memcpy (out, &new_value, HBINT16::static_size); out += HBINT16::static_size; new_value = new_y; - memcpy (out, &new_value, HBINT16::static_size); + hb_memcpy (out, &new_value, HBINT16::static_size); out += HBINT16::static_size; - memcpy (out, p+2, len - len_before_val - 2); + hb_memcpy (out, p+2, len - len_before_val - 2); len += 2; } } @@ -170,6 +212,7 @@ struct CompositeGlyphRecord bool scaled_offsets () const { return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; } + public: bool get_transformation (float (&matrix)[4], contour_point_t &trans) const { matrix[0] = matrix[3] = 1.f; @@ -197,7 +240,8 @@ struct CompositeGlyphRecord } if (is_anchored ()) tx = ty = 0; - trans.init ((float) tx, (float) ty); + /* set is_end_point flag to true, used by IUP delta optimization */ + trans.init ((float) tx, (float) ty, true); { const F2DOT14 *points = (const F2DOT14 *) p; @@ -224,7 +268,6 @@ struct CompositeGlyphRecord return tx || ty; } - public: hb_codepoint_t get_gid () const { #ifndef HB_NO_BEYOND_64K @@ -245,63 +288,36 @@ struct CompositeGlyphRecord StructAfter (flags) = gid; } - protected: - HBUINT16 flags; - HBUINT24 pad; - public: - DEFINE_SIZE_MIN (4); -}; - -struct composite_iter_t : hb_iter_with_fallback_t -{ - typedef const CompositeGlyphRecord *__item_t__; - composite_iter_t (hb_bytes_t glyph_, __item_t__ current_) : - glyph (glyph_), current (nullptr), current_size (0) - { - set_current (current_); - } - - composite_iter_t () : glyph (hb_bytes_t ()), current (nullptr), current_size (0) {} - - item_t __item__ () const { return *current; } - bool __more__ () const { return current; } - void __next__ () +#ifndef HB_NO_BEYOND_64K + void lower_gid_24_to_16 () { - if (!current->has_more ()) { current = nullptr; return; } + hb_codepoint_t gid = get_gid (); + if (!(flags & GID_IS_24BIT) || gid > 0xFFFFu) + return; - set_current (&StructAtOffset (current, current_size)); - } - composite_iter_t __end__ () const { return composite_iter_t (); } - bool operator != (const composite_iter_t& o) const - { return current != o.current; } + /* Lower the flag and move the rest of the struct down. */ + unsigned size = get_size (); + char *end = (char *) this + size; + char *p = &StructAfter (flags); + p += HBGlyphID24::static_size; - void set_current (__item_t__ current_) - { - if (!glyph.check_range (current_, CompositeGlyphRecord::min_size)) - { - current = nullptr; - current_size = 0; - return; - } - unsigned size = current_->get_size (); - if (!glyph.check_range (current_, size)) - { - current = nullptr; - current_size = 0; - return; - } + flags = flags & ~GID_IS_24BIT; + set_gid (gid); - current = current_; - current_size = size; + memmove (p - HBGlyphID24::static_size + HBGlyphID16::static_size, p, end - p); } +#endif - private: - hb_bytes_t glyph; - __item_t__ current; - unsigned current_size; + protected: + HBUINT16 flags; + HBUINT24 pad; + public: + DEFINE_SIZE_MIN (4); }; +using composite_iter_t = composite_iter_tmpl; + struct CompositeGlyph { const GlyphHeader &header; @@ -351,7 +367,7 @@ struct CompositeGlyph } bool compile_bytes_with_deltas (const hb_bytes_t &source_bytes, - const contour_point_vector_t &deltas, + const contour_point_vector_t &points_with_deltas, hb_bytes_t &dest_bytes /* OUT */) { if (source_bytes.length <= GlyphHeader::static_size || @@ -366,7 +382,7 @@ struct CompositeGlyph /* try to allocate more memories than source glyph bytes * in case that there might be an overflow for int8 value * and we would need to use int16 instead */ - char *o = (char *) hb_calloc (source_len + source_len/2, sizeof (char)); + char *o = (char *) hb_calloc (source_len * 2, sizeof (char)); if (unlikely (!o)) return false; const CompositeGlyphRecord *c = reinterpret_cast (source_bytes.arrayZ + GlyphHeader::static_size); @@ -376,18 +392,21 @@ struct CompositeGlyph unsigned i = 0, source_comp_len = 0; for (const auto &component : it) { - /* last 4 points in deltas are phantom points and should not be included */ - if (i >= deltas.length - 4) return false; + /* last 4 points in points_with_deltas are phantom points and should not be included */ + if (i >= points_with_deltas.length - 4) { + hb_free (o); + return false; + } unsigned comp_len = component.get_size (); if (component.is_anchored ()) { - memcpy (p, &component, comp_len); + hb_memcpy (p, &component, comp_len); p += comp_len; } else { - unsigned new_len = component.compile_with_deltas (deltas[i], p); + unsigned new_len = component.compile_with_point (points_with_deltas[i], p); p += new_len; } i++; @@ -398,7 +417,7 @@ struct CompositeGlyph if (source_len > source_comp_len) { unsigned instr_len = source_len - source_comp_len; - memcpy (p, (const char *)c + source_comp_len, instr_len); + hb_memcpy (p, (const char *)c + source_comp_len, instr_len); p += instr_len; } diff --git a/libs/harfbuzz/src/OT/glyf/Glyph.hh b/libs/harfbuzz/src/OT/glyf/Glyph.hh index 0b25659ac..7772597e5 100644 --- a/libs/harfbuzz/src/OT/glyf/Glyph.hh +++ b/libs/harfbuzz/src/OT/glyf/Glyph.hh @@ -27,7 +27,11 @@ enum phantom_point_index_t struct Glyph { - enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE }; + enum glyph_type_t { + EMPTY, + SIMPLE, + COMPOSITE, + }; public: composite_iter_t get_composite_iterator () const @@ -41,6 +45,7 @@ struct Glyph switch (type) { case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding (); case SIMPLE: return SimpleGlyph (*header, bytes).trim_padding (); + case EMPTY: return bytes; default: return bytes; } } @@ -50,7 +55,7 @@ struct Glyph switch (type) { case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return; case SIMPLE: SimpleGlyph (*header, bytes).drop_hints (); return; - default: return; + case EMPTY: return; } } @@ -59,7 +64,7 @@ struct Glyph switch (type) { case COMPOSITE: CompositeGlyph (*header, bytes).set_overlaps_flag (); return; case SIMPLE: SimpleGlyph (*header, bytes).set_overlaps_flag (); return; - default: return; + case EMPTY: return; } } @@ -68,33 +73,97 @@ struct Glyph switch (type) { case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return; case SIMPLE: SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return; - default: return; + case EMPTY: return; } } + bool is_composite () const + { return type == COMPOSITE; } + + bool get_all_points_without_var (const hb_face_t *face, + contour_point_vector_t &points /* OUT */) const + { + switch (type) { + case SIMPLE: + if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points))) + return false; + break; + case COMPOSITE: + { + for (auto &item : get_composite_iterator ()) + if (unlikely (!item.get_points (points))) return false; + break; + } + case EMPTY: + break; + } + + /* Init phantom points */ + if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false; + hb_array_t phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT); + { + int lsb = 0; + int h_delta = face->table.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb) ? + (int) header->xMin - lsb : 0; + HB_UNUSED int tsb = 0; + int v_orig = (int) header->yMax + +#ifndef HB_NO_VERTICAL + ((void) face->table.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb), tsb) +#else + 0 +#endif + ; + unsigned h_adv = face->table.hmtx->get_advance_without_var_unscaled (gid); + unsigned v_adv = +#ifndef HB_NO_VERTICAL + face->table.vmtx->get_advance_without_var_unscaled (gid) +#else + - face->get_upem () +#endif + ; + phantoms[PHANTOM_LEFT].x = h_delta; + phantoms[PHANTOM_RIGHT].x = (int) h_adv + h_delta; + phantoms[PHANTOM_TOP].y = v_orig; + phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv; + } + return true; + } + void update_mtx (const hb_subset_plan_t *plan, - int xMin, int yMax, + int xMin, int xMax, + int yMin, int yMax, const contour_point_vector_t &all_points) const { hb_codepoint_t new_gid = 0; if (!plan->new_gid_for_old_gid (gid, &new_gid)) return; + if (type != EMPTY) + { + plan->bounds_width_vec[new_gid] = xMax - xMin; + plan->bounds_height_vec[new_gid] = yMax - yMin; + } + unsigned len = all_points.length; float leftSideX = all_points[len - 4].x; float rightSideX = all_points[len - 3].x; float topSideY = all_points[len - 2].y; float bottomSideY = all_points[len - 1].y; - int hori_aw = roundf (rightSideX - leftSideX); + uint32_t hash = hb_hash (new_gid); + + signed hori_aw = roundf (rightSideX - leftSideX); if (hori_aw < 0) hori_aw = 0; int lsb = roundf (xMin - leftSideX); - plan->hmtx_map->set (new_gid, hb_pair (hori_aw, lsb)); + plan->hmtx_map.set_with_hash (new_gid, hash, hb_pair ((unsigned) hori_aw, lsb)); + //flag value should be computed using non-empty glyphs + if (type != EMPTY && lsb != xMin) + plan->head_maxp_info.allXMinIsLsb = false; - int vert_aw = roundf (topSideY - bottomSideY); + signed vert_aw = roundf (topSideY - bottomSideY); if (vert_aw < 0) vert_aw = 0; int tsb = roundf (topSideY - yMax); - plan->vmtx_map->set (new_gid, hb_pair (vert_aw, tsb)); + plan->vmtx_map.set_with_hash (new_gid, hash, hb_pair ((unsigned) vert_aw, tsb)); } bool compile_header_bytes (const hb_subset_plan_t *plan, @@ -102,42 +171,61 @@ struct Glyph hb_bytes_t &dest_bytes /* OUT */) const { GlyphHeader *glyph_header = nullptr; - if (type != EMPTY && all_points.length > 4) + if (!plan->pinned_at_default && type != EMPTY && all_points.length >= 4) { glyph_header = (GlyphHeader *) hb_calloc (1, GlyphHeader::static_size); if (unlikely (!glyph_header)) return false; } - int xMin = 0, xMax = 0; - int yMin = 0, yMax = 0; + float xMin = 0, xMax = 0; + float yMin = 0, yMax = 0; if (all_points.length > 4) { - xMin = xMax = roundf (all_points[0].x); - yMin = yMax = roundf (all_points[0].y); + xMin = xMax = all_points[0].x; + yMin = yMax = all_points[0].y; + + unsigned count = all_points.length - 4; + for (unsigned i = 1; i < count; i++) + { + float x = all_points[i].x; + float y = all_points[i].y; + xMin = hb_min (xMin, x); + xMax = hb_max (xMax, x); + yMin = hb_min (yMin, y); + yMax = hb_max (yMax, y); + } } - for (unsigned i = 1; i < all_points.length - 4; i++) + + // These are destined for storage in a 16 bit field to clamp the values to + // fit into a 16 bit signed integer. + int rounded_xMin = hb_clamp (roundf (xMin), -32768.0f, 32767.0f); + int rounded_xMax = hb_clamp (roundf (xMax), -32768.0f, 32767.0f); + int rounded_yMin = hb_clamp (roundf (yMin), -32768.0f, 32767.0f); + int rounded_yMax = hb_clamp (roundf (yMax), -32768.0f, 32767.0f); + + update_mtx (plan, rounded_xMin, rounded_xMax, rounded_yMin, rounded_yMax, all_points); + + if (type != EMPTY) { - float rounded_x = roundf (all_points[i].x); - float rounded_y = roundf (all_points[i].y); - xMin = hb_min (xMin, rounded_x); - xMax = hb_max (xMax, rounded_x); - yMin = hb_min (yMin, rounded_y); - yMax = hb_max (yMax, rounded_y); + plan->head_maxp_info.xMin = hb_min (plan->head_maxp_info.xMin, rounded_xMin); + plan->head_maxp_info.yMin = hb_min (plan->head_maxp_info.yMin, rounded_yMin); + plan->head_maxp_info.xMax = hb_max (plan->head_maxp_info.xMax, rounded_xMax); + plan->head_maxp_info.yMax = hb_max (plan->head_maxp_info.yMax, rounded_yMax); } - update_mtx (plan, xMin, yMax, all_points); - - /*for empty glyphs: all_points only include phantom points. - *just update metrics and then return */ + /* when pinned at default, no need to compile glyph header + * and for empty glyphs: all_points only include phantom points. + * just update metrics and then return */ if (!glyph_header) return true; glyph_header->numberOfContours = header->numberOfContours; - glyph_header->xMin = xMin; - glyph_header->yMin = yMin; - glyph_header->xMax = xMax; - glyph_header->yMax = yMax; + + glyph_header->xMin = rounded_xMin; + glyph_header->yMin = rounded_yMin; + glyph_header->xMax = rounded_xMax; + glyph_header->yMax = rounded_yMax; dest_bytes = hb_bytes_t ((const char *)glyph_header, GlyphHeader::static_size); return true; @@ -149,35 +237,57 @@ struct Glyph hb_bytes_t &dest_start, /* IN/OUT */ hb_bytes_t &dest_end /* OUT */) { - contour_point_vector_t all_points, deltas; - if (!get_points (font, glyf, all_points, &deltas, false, false)) + contour_point_vector_t all_points, points_with_deltas; + unsigned composite_contours = 0; + head_maxp_info_t *head_maxp_info_p = &plan->head_maxp_info; + unsigned *composite_contours_p = &composite_contours; + + // don't compute head/maxp values when glyph has no contours(type is EMPTY) + // also ignore .notdef glyph when --notdef-outline is not enabled + if (type == EMPTY || + (gid == 0 && !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))) + { + head_maxp_info_p = nullptr; + composite_contours_p = nullptr; + } + + if (!get_points (font, glyf, all_points, &points_with_deltas, head_maxp_info_p, composite_contours_p, false, false)) return false; // .notdef, set type to empty so we only update metrics and don't compile bytes for // it if (gid == 0 && !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) + { type = EMPTY; - - switch (type) { - case COMPOSITE: - if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start, - deltas, - dest_end)) - return false; - break; - case SIMPLE: - if (!SimpleGlyph (*header, bytes).compile_bytes_with_deltas (all_points, - plan->flags & HB_SUBSET_FLAGS_NO_HINTING, - dest_end)) - return false; - break; - default: - /* set empty bytes for empty glyph - * do not use source glyph's pointers */ dest_start = hb_bytes_t (); dest_end = hb_bytes_t (); - break; + } + + //dont compile bytes when pinned at default, just recalculate bounds + if (!plan->pinned_at_default) + { + switch (type) + { + case COMPOSITE: + if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start, + points_with_deltas, + dest_end)) + return false; + break; + case SIMPLE: + if (!SimpleGlyph (*header, bytes).compile_bytes_with_deltas (all_points, + plan->flags & HB_SUBSET_FLAGS_NO_HINTING, + dest_end)) + return false; + break; + case EMPTY: + /* set empty bytes for empty glyph + * do not use source glyph's pointers */ + dest_start = hb_bytes_t (); + dest_end = hb_bytes_t (); + break; + } } if (!compile_header_bytes (plan, all_points, dest_start)) @@ -195,40 +305,66 @@ struct Glyph template bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator, contour_point_vector_t &all_points /* OUT */, - contour_point_vector_t *deltas = nullptr, /* OUT */ + contour_point_vector_t *points_with_deltas = nullptr, /* OUT */ + head_maxp_info_t * head_maxp_info = nullptr, /* OUT */ + unsigned *composite_contours = nullptr, /* OUT */ bool shift_points_hori = true, bool use_my_metrics = true, bool phantom_only = false, - unsigned int depth = 0) const + hb_array_t coords = hb_array_t (), + hb_map_t *current_glyphs = nullptr, + unsigned int depth = 0, + unsigned *edge_count = nullptr) const { if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false; + unsigned stack_edge_count = 0; + if (!edge_count) edge_count = &stack_edge_count; + if (unlikely (*edge_count > HB_MAX_GRAPH_EDGE_COUNT)) return false; + (*edge_count)++; + + hb_map_t current_glyphs_stack; + if (current_glyphs == nullptr) + current_glyphs = ¤t_glyphs_stack; + + if (head_maxp_info) + { + head_maxp_info->maxComponentDepth = hb_max (head_maxp_info->maxComponentDepth, depth); + } + + if (!coords) + coords = hb_array (font->coords, font->num_coords); + contour_point_vector_t stack_points; - bool inplace = type == SIMPLE && all_points.length == 0; - /* Load into all_points if it's empty, as an optimization. */ - contour_point_vector_t &points = inplace ? all_points : stack_points; + contour_point_vector_t &points = type == SIMPLE ? all_points : stack_points; + unsigned old_length = points.length; switch (type) { + case SIMPLE: + if (depth == 0 && head_maxp_info) + head_maxp_info->maxContours = hb_max (head_maxp_info->maxContours, (unsigned) header->numberOfContours); + if (depth > 0 && composite_contours) + *composite_contours += (unsigned) header->numberOfContours; + if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (all_points, phantom_only))) + return false; + break; case COMPOSITE: { - /* pseudo component points for each component in composite glyph */ - unsigned num_points = hb_len (CompositeGlyph (*header, bytes).iter ()); - if (unlikely (!points.resize (num_points))) return false; + for (auto &item : get_composite_iterator ()) + if (unlikely (!item.get_points (points))) return false; break; } - case SIMPLE: - if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only))) - return false; + case EMPTY: break; } /* Init phantom points */ if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false; - hb_array_t phantoms = points.sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT); + hb_array_t phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT); { int lsb = 0; int h_delta = glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb) ? (int) header->xMin - lsb : 0; - int tsb = 0; + HB_UNUSED int tsb = 0; int v_orig = (int) header->yMax + #ifndef HB_NO_VERTICAL ((void) glyf_accelerator.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb), tsb) @@ -245,56 +381,84 @@ struct Glyph #endif ; phantoms[PHANTOM_LEFT].x = h_delta; - phantoms[PHANTOM_RIGHT].x = h_adv + h_delta; + phantoms[PHANTOM_RIGHT].x = (int) h_adv + h_delta; phantoms[PHANTOM_TOP].y = v_orig; phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv; } - if (deltas != nullptr && depth == 0 && type == COMPOSITE) - { - if (unlikely (!deltas->resize (points.length))) return false; - deltas->copy_vector (points); - } - #ifndef HB_NO_VAR - glyf_accelerator.gvar->apply_deltas_to_points (gid, font, points.as_array ()); + if (coords) + 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 (deltas != nullptr && depth == 0 && type == COMPOSITE) + if (points_with_deltas != nullptr && depth == 0 && type == COMPOSITE) { - for (unsigned i = 0 ; i < points.length; i++) - { - deltas->arrayZ[i].x = points.arrayZ[i].x - deltas->arrayZ[i].x; - deltas->arrayZ[i].y = points.arrayZ[i].y - deltas->arrayZ[i].y; - } + if (unlikely (!points_with_deltas->resize (points.length))) return false; + *points_with_deltas = points; } switch (type) { case SIMPLE: - if (!inplace) - all_points.extend (points.as_array ()); + if (depth == 0 && head_maxp_info) + head_maxp_info->maxPoints = hb_max (head_maxp_info->maxPoints, all_points.length - old_length - 4); break; case COMPOSITE: { - contour_point_vector_t comp_points; unsigned int comp_index = 0; for (auto &item : get_composite_iterator ()) { - comp_points.reset (); - if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ()) - .get_points (font, glyf_accelerator, comp_points, - deltas, shift_points_hori, use_my_metrics, phantom_only, depth + 1))) + hb_codepoint_t item_gid = item.get_gid (); + + if (unlikely (current_glyphs->has (item_gid))) + continue; + + current_glyphs->add (item_gid); + + unsigned old_count = all_points.length; + + if (unlikely ((!phantom_only || (use_my_metrics && item.is_use_my_metrics ())) && + !glyf_accelerator.glyph_for_gid (item_gid) + .get_points (font, + glyf_accelerator, + all_points, + points_with_deltas, + head_maxp_info, + composite_contours, + shift_points_hori, + use_my_metrics, + phantom_only, + coords, + current_glyphs, + depth + 1, + edge_count))) + { + current_glyphs->del (item_gid); return false; + } - /* Apply component transformation & translation */ - item.transform_points (comp_points); + auto comp_points = all_points.as_array ().sub_array (old_count); - /* Apply translation from gvar */ - comp_points.translate (points[comp_index]); + /* Copy phantom points from component if USE_MY_METRICS flag set */ + if (use_my_metrics && item.is_use_my_metrics ()) + for (unsigned int i = 0; i < PHANTOM_COUNT; i++) + phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i]; - if (item.is_anchored ()) + if (comp_points) // Empty in case of phantom_only + { + float matrix[4]; + contour_point_t default_trans; + item.get_transformation (matrix, default_trans); + + /* Apply component transformation & translation (with deltas applied) */ + item.transform_points (comp_points, matrix, points[comp_index]); + } + + if (item.is_anchored () && !phantom_only) { unsigned int p1, p2; item.get_anchor_points (p1, p2); @@ -304,24 +468,34 @@ struct Glyph delta.init (all_points[p1].x - comp_points[p2].x, all_points[p1].y - comp_points[p2].y); - comp_points.translate (delta); + item.translate (delta, comp_points); } } - /* Copy phantom points from component if USE_MY_METRICS flag set */ - if (use_my_metrics && item.is_use_my_metrics ()) - for (unsigned int i = 0; i < PHANTOM_COUNT; i++) - phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i]; + all_points.resize (all_points.length - PHANTOM_COUNT); - all_points.extend (comp_points.sub_array (0, comp_points.length - PHANTOM_COUNT)); + if (all_points.length > HB_GLYF_MAX_POINTS) + { + current_glyphs->del (item_gid); + return false; + } comp_index++; + current_glyphs->del (item_gid); } + if (head_maxp_info && depth == 0) + { + if (composite_contours) + head_maxp_info->maxCompositeContours = hb_max (head_maxp_info->maxCompositeContours, *composite_contours); + head_maxp_info->maxCompositePoints = hb_max (head_maxp_info->maxCompositePoints, all_points.length); + head_maxp_info->maxComponentElements = hb_max (head_maxp_info->maxComponentElements, comp_index); + } all_points.extend (phantoms); } break; - default: + case EMPTY: all_points.extend (phantoms); + break; } if (depth == 0 && shift_points_hori) /* Apply at top level */ @@ -329,9 +503,10 @@ struct Glyph /* Undocumented rasterizer behavior: * Shift points horizontally by the updated left side bearing */ - contour_point_t delta; - delta.init (-phantoms[PHANTOM_LEFT].x, 0.f); - if (delta.x) all_points.translate (delta); + float v = -phantoms[PHANTOM_LEFT].x; + if (v) + for (auto &point : all_points) + point.x += v; } return !all_points.in_error (); @@ -345,6 +520,8 @@ struct Glyph } hb_bytes_t get_bytes () const { return bytes; } + glyph_type_t get_type () const { return type; } + const GlyphHeader *get_header () const { return header; } Glyph () : bytes (), header (bytes.as ()), @@ -360,14 +537,15 @@ struct Glyph int num_contours = header->numberOfContours; if (unlikely (num_contours == 0)) type = EMPTY; else if (num_contours > 0) type = SIMPLE; - else type = COMPOSITE; /* negative numbers */ + else if (num_contours <= -1) type = COMPOSITE; + else type = EMPTY; // Spec deviation; Spec says COMPOSITE, but not seen in the wild. } protected: hb_bytes_t bytes; const GlyphHeader *header; hb_codepoint_t gid; - unsigned type; + glyph_type_t type; }; diff --git a/libs/harfbuzz/src/OT/glyf/GlyphHeader.hh b/libs/harfbuzz/src/OT/glyf/GlyphHeader.hh index e4a9168b7..a43b6691a 100644 --- a/libs/harfbuzz/src/OT/glyf/GlyphHeader.hh +++ b/libs/harfbuzz/src/OT/glyf/GlyphHeader.hh @@ -21,10 +21,12 @@ struct GlyphHeader /* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */ int lsb = hb_min (xMin, xMax); (void) glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb); - extents->x_bearing = font->em_scale_x (lsb); - extents->y_bearing = font->em_scale_y (hb_max (yMin, yMax)); - extents->width = font->em_scale_x (hb_max (xMin, xMax) - hb_min (xMin, xMax)); - extents->height = font->em_scale_y (hb_min (yMin, yMax) - hb_max (yMin, yMax)); + extents->x_bearing = lsb; + extents->y_bearing = hb_max (yMin, yMax); + extents->width = hb_max (xMin, xMax) - hb_min (xMin, xMax); + extents->height = hb_min (yMin, yMax) - hb_max (yMin, yMax); + + font->scale_glyph_extents (extents); return true; } diff --git a/libs/harfbuzz/src/OT/glyf/SimpleGlyph.hh b/libs/harfbuzz/src/OT/glyf/SimpleGlyph.hh index d45f4eb35..1d42cc292 100644 --- a/libs/harfbuzz/src/OT/glyf/SimpleGlyph.hh +++ b/libs/harfbuzz/src/OT/glyf/SimpleGlyph.hh @@ -20,7 +20,7 @@ struct SimpleGlyph FLAG_X_SAME = 0x10, FLAG_Y_SAME = 0x20, FLAG_OVERLAP_SIMPLE = 0x40, - FLAG_RESERVED2 = 0x80 + FLAG_CUBIC = 0x80 }; const GlyphHeader &header; @@ -34,6 +34,11 @@ struct SimpleGlyph unsigned int length (unsigned int instruction_len) const { return instruction_len_offset () + 2 + instruction_len; } + bool has_instructions_length () const + { + return instruction_len_offset () + 2 <= bytes.length; + } + unsigned int instructions_length () const { unsigned int instruction_length_offset = instruction_len_offset (); @@ -94,6 +99,7 @@ struct SimpleGlyph /* zero instruction length */ void drop_hints () { + if (!has_instructions_length ()) return; GlyphHeader &glyph_header = const_cast (header); (HBUINT16 &) StructAtOffset (&glyph_header, instruction_len_offset ()) = 0; } @@ -118,7 +124,7 @@ struct SimpleGlyph } static bool read_flags (const HBUINT8 *&p /* IN/OUT */, - contour_point_vector_t &points_ /* IN/OUT */, + hb_array_t points_ /* IN/OUT */, const HBUINT8 *end) { unsigned count = points_.length; @@ -132,15 +138,15 @@ struct SimpleGlyph if (unlikely (p + 1 > end)) return false; unsigned int repeat_count = *p++; unsigned stop = hb_min (i + repeat_count, count); - for (; i < stop;) - points_.arrayZ[i++].flag = flag; + for (; i < stop; i++) + points_.arrayZ[i].flag = flag; } } return true; } static bool read_points (const HBUINT8 *&p /* IN/OUT */, - contour_point_vector_t &points_ /* IN/OUT */, + hb_array_t points_ /* IN/OUT */, const HBUINT8 *end, float contour_point_t::*m, const simple_glyph_flag_t short_flag, @@ -148,10 +154,9 @@ struct SimpleGlyph { int v = 0; - unsigned count = points_.length; - for (unsigned i = 0; i < count; i++) + for (auto &point : points_) { - unsigned flag = points_[i].flag; + unsigned flag = point.flag; if (flag & short_flag) { if (unlikely (p + 1 > end)) return false; @@ -169,23 +174,27 @@ struct SimpleGlyph p += HBINT16::static_size; } } - points_.arrayZ[i].*m = v; + point.*m = v; } return true; } - bool get_contour_points (contour_point_vector_t &points_ /* OUT */, + bool get_contour_points (contour_point_vector_t &points /* OUT */, bool phantom_only = false) const { const HBUINT16 *endPtsOfContours = &StructAfter (header); int num_contours = header.numberOfContours; - assert (num_contours); + assert (num_contours > 0); /* One extra item at the end, for the instruction-count below. */ if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours]))) return false; unsigned int num_points = endPtsOfContours[num_contours - 1] + 1; - points_.alloc (num_points + 4); // Allocate for phantom points, to avoid a possible copy - if (!points_.resize (num_points)) return false; + unsigned old_length = points.length; + points.alloc (points.length + num_points + 4, true); // Allocate for phantom points, to avoid a possible copy + if (unlikely (!points.resize (points.length + num_points, false))) return false; + auto points_ = points.as_array ().sub_array (old_length); + if (!phantom_only) + hb_memset (points_.arrayZ, 0, sizeof (contour_point_t) * num_points); if (phantom_only) return true; for (int i = 0; i < num_contours; i++) @@ -208,7 +217,7 @@ struct SimpleGlyph } static void encode_coord (int value, - uint8_t &flag, + unsigned &flag, const simple_glyph_flag_t short_flag, const simple_glyph_flag_t same_flag, hb_vector_t &coords /* OUT */) @@ -223,41 +232,41 @@ struct SimpleGlyph if (value > 0) flag |= same_flag; else value = -value; - coords.push ((uint8_t)value); + coords.arrayZ[coords.length++] = (uint8_t) value; } else { int16_t val = value; - coords.push (val >> 8); - coords.push (val & 0xff); + coords.arrayZ[coords.length++] = val >> 8; + coords.arrayZ[coords.length++] = val & 0xff; } } - static void encode_flag (uint8_t &flag, - uint8_t &repeat, - uint8_t &lastflag, + static void encode_flag (unsigned flag, + unsigned &repeat, + unsigned lastflag, hb_vector_t &flags /* OUT */) { if (flag == lastflag && repeat != 255) { - repeat = repeat + 1; + repeat++; if (repeat == 1) { - flags.push(flag); + /* We know there's room. */ + flags.arrayZ[flags.length++] = flag; } else { unsigned len = flags.length; - flags[len-2] = flag | FLAG_REPEAT; - flags[len-1] = repeat; + flags.arrayZ[len-2] = flag | FLAG_REPEAT; + flags.arrayZ[len-1] = repeat; } } else { repeat = 0; - flags.push (flag); + flags.arrayZ[flags.length++] = flag; } - lastflag = flag; } bool compile_bytes_with_deltas (const contour_point_vector_t &all_points, @@ -269,31 +278,30 @@ struct SimpleGlyph dest_bytes = hb_bytes_t (); return true; } - //convert absolute values to relative values unsigned num_points = all_points.length - 4; hb_vector_t flags, x_coords, y_coords; - if (unlikely (!flags.alloc (num_points))) return false; - if (unlikely (!x_coords.alloc (2*num_points))) return false; - if (unlikely (!y_coords.alloc (2*num_points))) return false; + if (unlikely (!flags.alloc (num_points, true))) return false; + if (unlikely (!x_coords.alloc (2*num_points, true))) return false; + if (unlikely (!y_coords.alloc (2*num_points, true))) return false; + + unsigned lastflag = 255, repeat = 0; + int prev_x = 0, prev_y = 0; - uint8_t lastflag = 0, repeat = 0; - int prev_x = 0.f, prev_y = 0.f; - for (unsigned i = 0; i < num_points; i++) { - uint8_t flag = all_points[i].flag; - flag &= FLAG_ON_CURVE + FLAG_OVERLAP_SIMPLE; + unsigned flag = all_points.arrayZ[i].flag; + flag &= FLAG_ON_CURVE | FLAG_OVERLAP_SIMPLE | FLAG_CUBIC; - float cur_x = roundf (all_points[i].x); - float cur_y = roundf (all_points[i].y); + int cur_x = roundf (all_points.arrayZ[i].x); + int cur_y = roundf (all_points.arrayZ[i].y); encode_coord (cur_x - prev_x, flag, FLAG_X_SHORT, FLAG_X_SAME, x_coords); encode_coord (cur_y - prev_y, flag, FLAG_Y_SHORT, FLAG_Y_SAME, y_coords); - if (i == 0) lastflag = flag + 1; //make lastflag != flag for the first point encode_flag (flag, repeat, lastflag, flags); prev_x = cur_x; prev_y = cur_y; + lastflag = flag; } unsigned len_before_instrs = 2 * header.numberOfContours + 2; @@ -303,29 +311,29 @@ struct SimpleGlyph if (!no_hinting) total_len += len_instrs; - char *p = (char *) hb_calloc (total_len, sizeof (char)); + char *p = (char *) hb_malloc (total_len); if (unlikely (!p)) return false; const char *src = bytes.arrayZ + GlyphHeader::static_size; char *cur = p; - memcpy (p, src, len_before_instrs); + hb_memcpy (p, src, len_before_instrs); cur += len_before_instrs; src += len_before_instrs; if (!no_hinting) { - memcpy (cur, src, len_instrs); + hb_memcpy (cur, src, len_instrs); cur += len_instrs; } - memcpy (cur, flags.arrayZ, flags.length); + hb_memcpy (cur, flags.arrayZ, flags.length); cur += flags.length; - memcpy (cur, x_coords.arrayZ, x_coords.length); + hb_memcpy (cur, x_coords.arrayZ, x_coords.length); cur += x_coords.length; - memcpy (cur, y_coords.arrayZ, y_coords.length); + hb_memcpy (cur, y_coords.arrayZ, y_coords.length); dest_bytes = hb_bytes_t (p, total_len); return true; diff --git a/libs/harfbuzz/src/OT/glyf/SubsetGlyph.hh b/libs/harfbuzz/src/OT/glyf/SubsetGlyph.hh index 88fc93c43..fe63066e4 100644 --- a/libs/harfbuzz/src/OT/glyf/SubsetGlyph.hh +++ b/libs/harfbuzz/src/OT/glyf/SubsetGlyph.hh @@ -18,6 +18,7 @@ struct SubsetGlyph Glyph source_glyph; hb_bytes_t dest_start; /* region of source_glyph to copy first */ hb_bytes_t dest_end; /* region of source_glyph to copy second */ + bool allocated; bool serialize (hb_serialize_context_t *c, bool use_short_loca, @@ -26,21 +27,26 @@ struct SubsetGlyph TRACE_SERIALIZE (this); hb_bytes_t dest_glyph = dest_start.copy (c); - dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length); + hb_bytes_t end_copy = dest_end.copy (c); + if (!end_copy.arrayZ || !dest_glyph.arrayZ) { + return false; + } + + dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + end_copy.length); unsigned int pad_length = use_short_loca ? padding () : 0; - DEBUG_MSG (SUBSET, nullptr, "serialize %d byte glyph, width %d pad %d", dest_glyph.length, dest_glyph.length + pad_length, pad_length); + DEBUG_MSG (SUBSET, nullptr, "serialize %u byte glyph, width %u pad %u", dest_glyph.length, dest_glyph.length + pad_length, pad_length); HBUINT8 pad; pad = 0; while (pad_length > 0) { - c->embed (pad); + (void) c->embed (pad); pad_length--; } if (unlikely (!dest_glyph.length)) return_trace (true); - /* update components gids */ + /* update components gids. */ for (auto &_ : Glyph (dest_glyph).get_composite_iterator ()) { hb_codepoint_t new_gid; @@ -48,6 +54,50 @@ struct SubsetGlyph const_cast (_).set_gid (new_gid); } +#ifndef HB_NO_BEYOND_64K + auto it = Glyph (dest_glyph).get_composite_iterator (); + if (it) + { + /* lower GID24 to GID16 in components if possible. */ + char *p = it ? (char *) &*it : nullptr; + char *q = p; + const char *end = dest_glyph.arrayZ + dest_glyph.length; + while (it) + { + auto &rec = const_cast (*it); + ++it; + + q += rec.get_size (); + + rec.lower_gid_24_to_16 (); + + unsigned size = rec.get_size (); + + memmove (p, &rec, size); + + p += size; + } + memmove (p, q, end - q); + p += end - q; + + /* We want to shorten the glyph, but we can't do that without + * updating the length in the loca table, which is already + * written out :-(. So we just fill the rest of the glyph with + * harmless instructions, since that's what they will be + * interpreted as. + * + * Should move the lowering to _populate_subset_glyphs() to + * fix this issue. */ + + hb_memset (p, 0x7A /* TrueType instruction ROFF; harmless */, end - p); + p += end - p; + dest_glyph = hb_bytes_t (dest_glyph.arrayZ, p - (char *) dest_glyph.arrayZ); + + // TODO: Padding; & trim serialized bytes. + // TODO: Update length in loca. Ugh. + } +#endif + if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING) Glyph (dest_glyph).drop_hints (); @@ -60,12 +110,18 @@ struct SubsetGlyph bool compile_bytes_with_deltas (const hb_subset_plan_t *plan, hb_font_t *font, const glyf_accelerator_t &glyf) - { return source_glyph.compile_bytes_with_deltas (plan, font, glyf, dest_start, dest_end); } + { + allocated = source_glyph.compile_bytes_with_deltas (plan, font, glyf, dest_start, dest_end); + return allocated; + } void free_compiled_bytes () { - dest_start.fini (); - dest_end.fini (); + if (likely (allocated)) { + allocated = false; + dest_start.fini (); + dest_end.fini (); + } } void drop_hints_bytes () diff --git a/libs/harfbuzz/src/OT/glyf/composite-iter.hh b/libs/harfbuzz/src/OT/glyf/composite-iter.hh new file mode 100644 index 000000000..d05701f3d --- /dev/null +++ b/libs/harfbuzz/src/OT/glyf/composite-iter.hh @@ -0,0 +1,68 @@ +#ifndef OT_GLYF_COMPOSITE_ITER_HH +#define OT_GLYF_COMPOSITE_ITER_HH + + +#include "../../hb.hh" + + +namespace OT { +namespace glyf_impl { + + +template +struct composite_iter_tmpl : hb_iter_with_fallback_t, + const CompositeGlyphRecord &> +{ + typedef const CompositeGlyphRecord *__item_t__; + composite_iter_tmpl (hb_bytes_t glyph_, __item_t__ current_) : + glyph (glyph_), current (nullptr), current_size (0) + { + set_current (current_); + } + + composite_iter_tmpl () : glyph (hb_bytes_t ()), current (nullptr), current_size (0) {} + + const CompositeGlyphRecord & __item__ () const { return *current; } + bool __more__ () const { return current; } + void __next__ () + { + if (!current->has_more ()) { current = nullptr; return; } + + set_current (&StructAtOffset (current, current_size)); + } + composite_iter_tmpl __end__ () const { return composite_iter_tmpl (); } + bool operator != (const composite_iter_tmpl& o) const + { return current != o.current; } + + + void set_current (__item_t__ current_) + { + if (!glyph.check_range (current_, CompositeGlyphRecord::min_size)) + { + current = nullptr; + current_size = 0; + return; + } + unsigned size = current_->get_size (); + if (!glyph.check_range (current_, size)) + { + current = nullptr; + current_size = 0; + return; + } + + current = current_; + current_size = size; + } + + private: + hb_bytes_t glyph; + __item_t__ current; + unsigned current_size; +}; + + +} /* namespace glyf_impl */ +} /* namespace OT */ + +#endif /* OT_GLYF_COMPOSITE_ITER_HH */ diff --git a/libs/harfbuzz/src/OT/glyf/glyf-helpers.hh b/libs/harfbuzz/src/OT/glyf/glyf-helpers.hh index 181c33d06..f157bf002 100644 --- a/libs/harfbuzz/src/OT/glyf/glyf-helpers.hh +++ b/libs/harfbuzz/src/OT/glyf/glyf-helpers.hh @@ -12,24 +12,44 @@ namespace OT { namespace glyf_impl { -template +template static void -_write_loca (IteratorIn&& it, bool short_offsets, IteratorOut&& dest) +_write_loca (IteratorIn&& it, + const hb_sorted_vector_t new_to_old_gid_list, + bool short_offsets, + TypeOut *dest, + unsigned num_offsets) { unsigned right_shift = short_offsets ? 1 : 0; - unsigned int offset = 0; - dest << 0; - + it - | hb_map ([=, &offset] (unsigned int padded_size) - { - offset += padded_size; - DEBUG_MSG (SUBSET, nullptr, "loca entry offset %d", offset); - return offset >> right_shift; - }) - | hb_sink (dest) - ; + unsigned offset = 0; + TypeOut value; + value = 0; + *dest++ = value; + hb_codepoint_t last = 0; + for (auto _ : new_to_old_gid_list) + { + hb_codepoint_t gid = _.first; + for (; last < gid; last++) + { + DEBUG_MSG (SUBSET, nullptr, "loca entry empty offset %u", offset); + *dest++ = value; + } + + unsigned padded_size = *it++; + offset += padded_size; + DEBUG_MSG (SUBSET, nullptr, "loca entry gid %" PRIu32 " offset %u padded-size %u", gid, offset, padded_size); + value = offset >> right_shift; + *dest++ = value; + + last++; // Skip over gid + } + unsigned num_glyphs = num_offsets - 1; + for (; last < num_glyphs; last++) + { + DEBUG_MSG (SUBSET, nullptr, "loca entry empty offset %u", offset); + *dest++ = value; + } } static bool @@ -44,6 +64,20 @@ _add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca) head *head_prime = (head *) hb_blob_get_data_writable (head_prime_blob, nullptr); head_prime->indexToLocFormat = use_short_loca ? 0 : 1; + if (plan->normalized_coords) + { + head_prime->xMin = plan->head_maxp_info.xMin; + head_prime->xMax = plan->head_maxp_info.xMax; + head_prime->yMin = plan->head_maxp_info.yMin; + head_prime->yMax = plan->head_maxp_info.yMax; + + unsigned orig_flag = head_prime->flags; + if (plan->head_maxp_info.allXMinIsLsb) + orig_flag |= 1 << 1; + else + orig_flag &= ~(1 << 1); + head_prime->flags = orig_flag; + } bool success = plan->add_table (HB_OT_TAG_head, head_prime_blob); hb_blob_destroy (head_prime_blob); @@ -53,21 +87,24 @@ _add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca) template static bool -_add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets, bool use_short_loca) +_add_loca_and_head (hb_subset_context_t *c, + Iterator padded_offsets, + bool use_short_loca) { - unsigned num_offsets = padded_offsets.len () + 1; + unsigned num_offsets = c->plan->num_output_glyphs () + 1; unsigned entry_size = use_short_loca ? 2 : 4; - char *loca_prime_data = (char *) hb_calloc (entry_size, num_offsets); + + char *loca_prime_data = (char *) hb_malloc (entry_size * num_offsets); if (unlikely (!loca_prime_data)) return false; - DEBUG_MSG (SUBSET, nullptr, "loca entry_size %d num_offsets %d size %d", + DEBUG_MSG (SUBSET, nullptr, "loca entry_size %u num_offsets %u size %u", entry_size, num_offsets, entry_size * num_offsets); if (use_short_loca) - _write_loca (padded_offsets, true, hb_array ((HBUINT16 *) loca_prime_data, num_offsets)); + _write_loca (padded_offsets, c->plan->new_to_old_gid_list, true, (HBUINT16 *) loca_prime_data, num_offsets); else - _write_loca (padded_offsets, false, hb_array ((HBUINT32 *) loca_prime_data, num_offsets)); + _write_loca (padded_offsets, c->plan->new_to_old_gid_list, false, (HBUINT32 *) loca_prime_data, num_offsets); hb_blob_t *loca_blob = hb_blob_create (loca_prime_data, entry_size * num_offsets, @@ -75,8 +112,8 @@ _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets, bool use_s loca_prime_data, hb_free); - bool result = plan->add_table (HB_OT_TAG_loca, loca_blob) - && _add_head_and_set_loca_version (plan, use_short_loca); + bool result = c->plan->add_table (HB_OT_TAG_loca, loca_blob) + && _add_head_and_set_loca_version (c->plan, use_short_loca); hb_blob_destroy (loca_blob); return result; diff --git a/libs/harfbuzz/src/OT/glyf/glyf.hh b/libs/harfbuzz/src/OT/glyf/glyf.hh index 5fb32f67f..f346ae05d 100644 --- a/libs/harfbuzz/src/OT/glyf/glyf.hh +++ b/libs/harfbuzz/src/OT/glyf/glyf.hh @@ -7,6 +7,7 @@ #include "../../hb-ot-hmtx-table.hh" #include "../../hb-ot-var-gvar-table.hh" #include "../../hb-draw.hh" +#include "../../hb-paint.hh" #include "glyf-helpers.hh" #include "Glyph.hh" @@ -30,6 +31,12 @@ struct glyf static constexpr hb_tag_t tableTag = HB_OT_TAG_glyf; + static bool has_valid_glyf_format(const hb_face_t* face) + { + const OT::head &head = *face->table.head; + return head.indexToLocFormat <= 1 && head.glyphDataFormat <= 1; + } + bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const { TRACE_SANITIZE (this); @@ -45,8 +52,11 @@ struct glyf const hb_subset_plan_t *plan) { TRACE_SERIALIZE (this); + unsigned init_len = c->length (); - for (const auto &_ : it) _.serialize (c, use_short_loca, plan); + for (auto &_ : it) + if (unlikely (!_.serialize (c, use_short_loca, plan))) + return false; /* As a special case when all glyph in the font are empty, add a zero byte * to the table, so that OTS doesn’t reject it, and to make the table work @@ -68,56 +78,79 @@ struct glyf { TRACE_SUBSET (this); - glyf *glyf_prime = c->serializer->start_embed (); - if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false); + if (!has_valid_glyf_format (c->plan->source)) { + // glyf format is unknown don't attempt to subset it. + DEBUG_MSG (SUBSET, nullptr, + "unkown glyf format, dropping from subset."); + return_trace (false); + } - hb_vector_t glyphs; - _populate_subset_glyphs (c->plan, glyphs); + hb_font_t *font = nullptr; + if (c->plan->normalized_coords) + { + font = _create_font_for_instancing (c->plan); + if (unlikely (!font)) + return_trace (false); + } + + hb_vector_t padded_offsets; + if (unlikely (!padded_offsets.alloc (c->plan->new_to_old_gid_list.length, true))) + return_trace (false); - if (!c->plan->pinned_at_default) + hb_vector_t glyphs; + if (!_populate_subset_glyphs (c->plan, font, glyphs)) { - if (!_compile_subset_glyphs_with_deltas (c->plan, &glyphs)) - return_trace (false); + hb_font_destroy (font); + return_trace (false); } - auto padded_offsets = - + hb_iter (glyphs) - | hb_map (&glyf_impl::SubsetGlyph::padded_size) - ; + if (font) + hb_font_destroy (font); - unsigned max_offset = + padded_offsets | hb_reduce (hb_add, 0); - bool use_short_loca = max_offset < 0x1FFFF; + unsigned max_offset = 0; + for (auto &g : glyphs) + { + unsigned size = g.padded_size (); + padded_offsets.push (size); + max_offset += size; + } + bool use_short_loca = false; + if (likely (!c->plan->force_long_loca)) + use_short_loca = max_offset < 0x1FFFF; - glyf_prime->serialize (c->serializer, hb_iter (glyphs), use_short_loca, c->plan); - if (!use_short_loca) { - padded_offsets = - + hb_iter (glyphs) - | hb_map (&glyf_impl::SubsetGlyph::length) - ; + if (!use_short_loca) + { + padded_offsets.resize (0); + for (auto &g : glyphs) + padded_offsets.push (g.length ()); } + auto *glyf_prime = c->serializer->start_embed (); + bool result = glyf_prime->serialize (c->serializer, hb_iter (glyphs), use_short_loca, c->plan); + if (c->plan->normalized_coords && !c->plan->pinned_at_default) + _free_compiled_subset_glyphs (glyphs); - if (!c->plan->pinned_at_default) - _free_compiled_subset_glyphs (&glyphs); - if (unlikely (c->serializer->in_error ())) return_trace (false); - return_trace (c->serializer->check_success (glyf_impl::_add_loca_and_head (c->plan, - padded_offsets, - use_short_loca))); + if (unlikely (!c->serializer->check_success (glyf_impl::_add_loca_and_head (c, + padded_offsets.iter (), + use_short_loca)))) + return_trace (false); + + return result; } - void + bool _populate_subset_glyphs (const hb_subset_plan_t *plan, - hb_vector_t &glyphs /* OUT */) const; + hb_font_t *font, + hb_vector_t& glyphs /* OUT */) const; - bool - _compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan, - hb_vector_t *glyphs /* OUT */) const; + hb_font_t * + _create_font_for_instancing (const hb_subset_plan_t *plan) const; - void _free_compiled_subset_glyphs (hb_vector_t *glyphs) const + void _free_compiled_subset_glyphs (hb_vector_t &glyphs) const { - for (auto _ : *glyphs) - _.free_compiled_bytes (); + for (auto &g : glyphs) + g.free_compiled_bytes (); } protected: @@ -145,7 +178,7 @@ struct glyf_accelerator_t vmtx = nullptr; #endif const OT::head &head = *face->table.head; - if (head.indexToLocFormat > 1 || head.glyphDataFormat > 0) + if (!glyf::has_valid_glyf_format (face)) /* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */ return; short_offset = 0 == head.indexToLocFormat; @@ -172,8 +205,12 @@ struct glyf_accelerator_t protected: template - bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer) const + bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer, + hb_array_t coords = hb_array_t ()) const { + if (!coords) + coords = hb_array (font->coords, font->num_coords); + if (gid >= num_glyphs) return false; /* Making this allocfree is not that easy @@ -183,16 +220,17 @@ struct glyf_accelerator_t contour_point_vector_t all_points; bool phantom_only = !consumer.is_consuming_contour_points (); - if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, true, true, phantom_only))) + 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; + assert (count >= glyf_impl::PHANTOM_COUNT); + count -= glyf_impl::PHANTOM_COUNT; + if (consumer.is_consuming_contour_points ()) { - unsigned count = all_points.length; - assert (count >= glyf_impl::PHANTOM_COUNT); - count -= glyf_impl::PHANTOM_COUNT; - for (unsigned point_index = 0; point_index < count; point_index++) - consumer.consume_point (all_points[point_index]); + for (auto &point : all_points.as_array ().sub_array (0, count)) + consumer.consume_point (point); consumer.points_end (); } @@ -200,11 +238,13 @@ struct glyf_accelerator_t contour_point_t *phantoms = consumer.get_phantoms_sink (); if (phantoms) for (unsigned i = 0; i < glyf_impl::PHANTOM_COUNT; ++i) - phantoms[i] = all_points[all_points.length - glyf_impl::PHANTOM_COUNT + i]; + phantoms[i] = all_points.arrayZ[count + i]; return true; } + public: + #ifndef HB_NO_VAR struct points_aggregator_t { @@ -237,19 +277,14 @@ struct glyf_accelerator_t extents->y_bearing = 0; return; } - if (scaled) - { - extents->x_bearing = font->em_scalef_x (min_x); - extents->width = font->em_scalef_x (max_x) - extents->x_bearing; - extents->y_bearing = font->em_scalef_y (max_y); - extents->height = font->em_scalef_y (min_y) - extents->y_bearing; - } - else { extents->x_bearing = roundf (min_x); extents->width = roundf (max_x - extents->x_bearing); extents->y_bearing = roundf (max_y); extents->height = roundf (min_y - extents->y_bearing); + + if (scaled) + font->scale_glyph_extents (extents); } } @@ -266,6 +301,7 @@ struct glyf_accelerator_t if (extents) bounds = contour_bounds_t (); } + HB_ALWAYS_INLINE void consume_point (const contour_point_t &point) { bounds.add (point); } void points_end () { bounds.get_extents (font, extents, scaled); } @@ -273,7 +309,6 @@ struct glyf_accelerator_t contour_point_t *get_phantoms_sink () { return phantoms; } }; - public: unsigned get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const { @@ -315,6 +350,15 @@ struct glyf_accelerator_t } #endif + bool get_leading_bearing_without_var_unscaled (hb_codepoint_t gid, bool is_vertical, int *lsb) const + { + if (unlikely (gid >= num_glyphs)) return false; + if (is_vertical) return false; // TODO Humm, what to do here? + + *lsb = glyph_for_gid (gid).get_header ()->xMin; + return true; + } + public: bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const { @@ -327,6 +371,15 @@ struct glyf_accelerator_t return glyph_for_gid (gid).get_extents_without_var_scaled (font, *this, extents); } + bool paint_glyph (hb_font_t *font, hb_codepoint_t gid, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const + { + funcs->push_clip_glyph (data, gid, font); + funcs->color (data, true, foreground); + funcs->pop_clip (data); + + return true; + } + const glyf_impl::Glyph glyph_for_gid (hb_codepoint_t gid, bool needs_padding_removal = false) const { @@ -359,6 +412,11 @@ struct glyf_accelerator_t get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const { 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 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; #endif @@ -375,66 +433,77 @@ struct glyf_accelerator_t }; -inline void +inline bool glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan, + hb_font_t *font, hb_vector_t& glyphs /* OUT */) const { OT::glyf_accelerator_t glyf (plan->source); - unsigned num_glyphs = plan->num_output_glyphs (); - if (!glyphs.resize (num_glyphs)) return; + if (!glyphs.alloc (plan->new_to_old_gid_list.length, true)) return false; - for (auto p : plan->glyph_map->iter ()) + for (const auto &pair : plan->new_to_old_gid_list) { - unsigned new_gid = p.second; - glyf_impl::SubsetGlyph& subset_glyph = glyphs.arrayZ[new_gid]; - subset_glyph.old_gid = p.first; + hb_codepoint_t new_gid = pair.first; + hb_codepoint_t old_gid = pair.second; + glyf_impl::SubsetGlyph *p = glyphs.push (); + glyf_impl::SubsetGlyph& subset_glyph = *p; + subset_glyph.old_gid = old_gid; - if (unlikely (new_gid == 0 && + if (unlikely (old_gid == 0 && new_gid == 0 && !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) && - plan->pinned_at_default) + !plan->normalized_coords) subset_glyph.source_glyph = glyf_impl::Glyph (); else - subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true); + { + /* If plan has an accelerator, the preprocessing step already trimmed glyphs. + * Don't trim them again! */ + subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, !plan->accelerator); + } if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING) subset_glyph.drop_hints_bytes (); else subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes (); + + if (font) + { + if (unlikely (!subset_glyph.compile_bytes_with_deltas (plan, font, glyf))) + { + // when pinned at default, only bounds are updated, thus no need to free + if (!plan->pinned_at_default) + _free_compiled_subset_glyphs (glyphs); + return false; + } + } } + return true; } -inline bool -glyf::_compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan, - hb_vector_t *glyphs /* OUT */) const +inline hb_font_t * +glyf::_create_font_for_instancing (const hb_subset_plan_t *plan) const { - OT::glyf_accelerator_t glyf (plan->source); hb_font_t *font = hb_font_create (plan->source); - if (unlikely (!font)) return false; + if (unlikely (font == hb_font_get_empty ())) return nullptr; hb_vector_t vars; - if (unlikely (!vars.alloc (plan->user_axes_location->get_population ()))) - return false; + if (unlikely (!vars.alloc (plan->user_axes_location.get_population (), true))) + { + hb_font_destroy (font); + return nullptr; + } - for (auto _ : *plan->user_axes_location) + for (auto _ : plan->user_axes_location) { hb_variation_t var; var.tag = _.first; - var.value = _.second; + var.value = _.second.middle; vars.push (var); } - hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location->get_population ()); - for (auto& subset_glyph : *glyphs) - { - if (!const_cast (subset_glyph).compile_bytes_with_deltas (plan, font, glyf)) - { - hb_font_destroy (font); - return false; - } - } - - hb_font_destroy (font); - return true; +#ifndef HB_NO_VAR + hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location.get_population ()); +#endif + return font; } diff --git a/libs/harfbuzz/src/OT/glyf/path-builder.hh b/libs/harfbuzz/src/OT/glyf/path-builder.hh index 9bfc45a1a..f55052450 100644 --- a/libs/harfbuzz/src/OT/glyf/path-builder.hh +++ b/libs/harfbuzz/src/OT/glyf/path-builder.hh @@ -21,29 +21,33 @@ struct path_builder_t operator bool () const { return has_data; } bool has_data = false; - float x = 0.; - float y = 0.; + float x; + float y; - optional_point_t lerp (optional_point_t p, float t) - { return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); } - } first_oncurve, first_offcurve, last_offcurve; + optional_point_t mid (optional_point_t p) + { return optional_point_t ((x + p.x) * 0.5f, (y + p.y) * 0.5f); } + } first_oncurve, first_offcurve, first_offcurve2, last_offcurve, last_offcurve2; - path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_) - { - font = font_; - draw_session = &draw_session_; - first_oncurve = first_offcurve = last_offcurve = optional_point_t (); - } + path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_) : + font (font_), draw_session (&draw_session_) {} /* based on https://github.com/RazrFalcon/ttf-parser/blob/4f32821/src/glyf.rs#L287 See also: * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html - * https://stackoverflow.com/a/20772557 */ + * https://stackoverflow.com/a/20772557 + * + * Cubic support added. */ + HB_ALWAYS_INLINE void consume_point (const contour_point_t &point) { bool is_on_curve = point.flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE; +#ifdef HB_NO_CUBIC_GLYF + bool is_cubic = false; +#else + bool is_cubic = !is_on_curve && (point.flag & glyf_impl::SimpleGlyph::FLAG_CUBIC); +#endif optional_point_t p (font->em_fscalef_x (point.x), font->em_fscalef_y (point.y)); - if (!first_oncurve) + if (unlikely (!first_oncurve)) { if (is_on_curve) { @@ -52,9 +56,14 @@ struct path_builder_t } else { - if (first_offcurve) + if (is_cubic && !first_offcurve2) + { + first_offcurve2 = first_offcurve; + first_offcurve = p; + } + else if (first_offcurve) { - optional_point_t mid = first_offcurve.lerp (p, .5f); + optional_point_t mid = first_offcurve.mid (p); first_oncurve = mid; last_offcurve = p; draw_session->move_to (mid.x, mid.y); @@ -69,16 +78,41 @@ struct path_builder_t { if (is_on_curve) { - draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, - p.x, p.y); + if (last_offcurve2) + { + draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y, + last_offcurve.x, last_offcurve.y, + p.x, p.y); + last_offcurve2 = optional_point_t (); + } + else + draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, + p.x, p.y); last_offcurve = optional_point_t (); } else { - optional_point_t mid = last_offcurve.lerp (p, .5f); - draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, - mid.x, mid.y); - last_offcurve = p; + if (is_cubic && !last_offcurve2) + { + last_offcurve2 = last_offcurve; + last_offcurve = p; + } + else + { + optional_point_t mid = last_offcurve.mid (p); + + if (is_cubic) + { + draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y, + last_offcurve.x, last_offcurve.y, + mid.x, mid.y); + last_offcurve2 = optional_point_t (); + } + else + draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, + mid.x, mid.y); + last_offcurve = p; + } } } else @@ -90,23 +124,44 @@ struct path_builder_t } } - if (point.is_end_point) + if (unlikely (point.is_end_point)) { if (first_offcurve && last_offcurve) { - optional_point_t mid = last_offcurve.lerp (first_offcurve, .5f); - draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, - mid.x, mid.y); + optional_point_t mid = last_offcurve.mid (first_offcurve2 ? + first_offcurve2 : + first_offcurve); + if (last_offcurve2) + draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y, + last_offcurve.x, last_offcurve.y, + mid.x, mid.y); + else + draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, + mid.x, mid.y); last_offcurve = optional_point_t (); - /* now check the rest */ } + /* now check the rest */ if (first_offcurve && first_oncurve) - draw_session->quadratic_to (first_offcurve.x, first_offcurve.y, - first_oncurve.x, first_oncurve.y); + { + if (first_offcurve2) + draw_session->cubic_to (first_offcurve2.x, first_offcurve2.y, + first_offcurve.x, first_offcurve.y, + first_oncurve.x, first_oncurve.y); + else + draw_session->quadratic_to (first_offcurve.x, first_offcurve.y, + first_oncurve.x, first_oncurve.y); + } else if (last_offcurve && first_oncurve) - draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, - first_oncurve.x, first_oncurve.y); + { + if (last_offcurve2) + draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y, + last_offcurve.x, last_offcurve.y, + first_oncurve.x, first_oncurve.y); + else + draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, + first_oncurve.x, first_oncurve.y); + } else if (first_oncurve) draw_session->line_to (first_oncurve.x, first_oncurve.y); else if (first_offcurve) @@ -117,7 +172,7 @@ struct path_builder_t } /* Getting ready for the next contour */ - first_oncurve = first_offcurve = last_offcurve = optional_point_t (); + first_oncurve = first_offcurve = last_offcurve = last_offcurve2 = optional_point_t (); draw_session->close_path (); } } diff --git a/libs/harfbuzz/src/OT/name/name.hh b/libs/harfbuzz/src/OT/name/name.hh new file mode 100644 index 000000000..e2a25d4a0 --- /dev/null +++ b/libs/harfbuzz/src/OT/name/name.hh @@ -0,0 +1,589 @@ +/* + * Copyright © 2011,2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef OT_NAME_NAME_HH +#define OT_NAME_NAME_HH + +#include "../../hb-open-type.hh" +#include "../../hb-ot-name-language.hh" +#include "../../hb-aat-layout.hh" +#include "../../hb-utf.hh" + + +namespace OT { + +template +inline unsigned int +hb_ot_name_convert_utf (hb_bytes_t bytes, + unsigned int *text_size /* IN/OUT */, + typename out_utf_t::codepoint_t *text /* OUT */) +{ + unsigned int src_len = bytes.length / sizeof (typename in_utf_t::codepoint_t); + const typename in_utf_t::codepoint_t *src = (const typename in_utf_t::codepoint_t *) bytes.arrayZ; + const typename in_utf_t::codepoint_t *src_end = src + src_len; + + typename out_utf_t::codepoint_t *dst = text; + + hb_codepoint_t unicode; + const hb_codepoint_t replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT; + + if (text_size && *text_size) + { + (*text_size)--; /* Save room for NUL-termination. */ + const typename out_utf_t::codepoint_t *dst_end = text + *text_size; + + while (src < src_end && dst < dst_end) + { + const typename in_utf_t::codepoint_t *src_next = in_utf_t::next (src, src_end, &unicode, replacement); + typename out_utf_t::codepoint_t *dst_next = out_utf_t::encode (dst, dst_end, unicode); + if (dst_next == dst) + break; /* Out-of-room. */ + + dst = dst_next; + src = src_next; + } + + *text_size = dst - text; + *dst = 0; /* NUL-terminate. */ + } + + /* Accumulate length of rest. */ + unsigned int dst_len = dst - text; + while (src < src_end) + { + src = in_utf_t::next (src, src_end, &unicode, replacement); + dst_len += out_utf_t::encode_len (unicode); + } + return dst_len; +} + +#define entry_score var.u16[0] +#define entry_index var.u16[1] + + +/* + * name -- Naming + * https://docs.microsoft.com/en-us/typography/opentype/spec/name + */ +#define HB_OT_TAG_name HB_TAG('n','a','m','e') + +#define UNSUPPORTED 42 + +struct NameRecord +{ + hb_language_t language (hb_face_t *face) const + { +#ifndef HB_NO_OT_NAME_LANGUAGE + unsigned int p = platformID; + unsigned int l = languageID; + + if (p == 3) + return _hb_ot_name_language_for_ms_code (l); + + if (p == 1) + return _hb_ot_name_language_for_mac_code (l); + +#ifndef HB_NO_OT_NAME_LANGUAGE_AAT + if (p == 0) + return face->table.ltag->get_language (l); +#endif + +#endif + return HB_LANGUAGE_INVALID; + } + + uint16_t score () const + { + /* Same order as in cmap::find_best_subtable(). */ + unsigned int p = platformID; + unsigned int e = encodingID; + + /* 32-bit. */ + if (p == 3 && e == 10) return 0; + if (p == 0 && e == 6) return 1; + if (p == 0 && e == 4) return 2; + + /* 16-bit. */ + if (p == 3 && e == 1) return 3; + if (p == 0 && e == 3) return 4; + if (p == 0 && e == 2) return 5; + if (p == 0 && e == 1) return 6; + if (p == 0 && e == 0) return 7; + + /* Symbol. */ + if (p == 3 && e == 0) return 8; + + /* We treat all Mac Latin names as ASCII only. */ + if (p == 1 && e == 0) return 10; /* 10 is magic number :| */ + + return UNSUPPORTED; + } + + NameRecord* copy (hb_serialize_context_t *c, const void *base +#ifdef HB_EXPERIMENTAL_API + , const hb_hashmap_t *name_table_overrides +#endif + ) const + { + TRACE_SERIALIZE (this); + HB_UNUSED auto snap = c->snapshot (); + auto *out = c->embed (this); + if (unlikely (!out)) return_trace (nullptr); +#ifdef HB_EXPERIMENTAL_API + hb_ot_name_record_ids_t record_ids (platformID, encodingID, languageID, nameID); + hb_bytes_t* name_bytes; + + if (name_table_overrides->has (record_ids, &name_bytes)) { + hb_bytes_t encoded_bytes = *name_bytes; + char *name_str_utf16_be = nullptr; + + if (platformID != 1) + { + unsigned text_size = hb_ot_name_convert_utf (*name_bytes, nullptr, nullptr); + + text_size++; // needs to consider NULL terminator for use in hb_ot_name_convert_utf() + unsigned byte_len = text_size * hb_utf16_be_t::codepoint_t::static_size; + name_str_utf16_be = (char *) hb_calloc (byte_len, 1); + if (!name_str_utf16_be) + { + c->revert (snap); + return_trace (nullptr); + } + hb_ot_name_convert_utf (*name_bytes, &text_size, + (hb_utf16_be_t::codepoint_t *) name_str_utf16_be); + + unsigned encoded_byte_len = text_size * hb_utf16_be_t::codepoint_t::static_size; + if (!encoded_byte_len || !c->check_assign (out->length, encoded_byte_len, HB_SERIALIZE_ERROR_INT_OVERFLOW)) { + c->revert (snap); + hb_free (name_str_utf16_be); + return_trace (nullptr); + } + + encoded_bytes = hb_bytes_t (name_str_utf16_be, encoded_byte_len); + } + else + { + // mac platform, copy the UTF-8 string(all ascii characters) as is + if (!c->check_assign (out->length, encoded_bytes.length, HB_SERIALIZE_ERROR_INT_OVERFLOW)) { + c->revert (snap); + return_trace (nullptr); + } + } + + out->offset = 0; + c->push (); + encoded_bytes.copy (c); + c->add_link (out->offset, c->pop_pack (), hb_serialize_context_t::Tail, 0); + hb_free (name_str_utf16_be); + } + else +#endif + { + out->offset.serialize_copy (c, offset, base, 0, hb_serialize_context_t::Tail, length); + } + return_trace (out); + } + + bool isUnicode () const + { + unsigned int p = platformID; + unsigned int e = encodingID; + + return (p == 0 || + (p == 3 && (e == 0 || e == 1 || e == 10))); + } + + static int cmp (const void *pa, const void *pb) + { + const NameRecord *a = (const NameRecord *)pa; + const NameRecord *b = (const NameRecord *)pb; + + if (a->platformID != b->platformID) + return a->platformID - b->platformID; + + if (a->encodingID != b->encodingID) + return a->encodingID - b->encodingID; + + if (a->languageID != b->languageID) + return a->languageID - b->languageID; + + if (a->nameID != b->nameID) + return a->nameID - b->nameID; + + if (a->length != b->length) + return a->length - b->length; + + return 0; + } + + bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + hb_barrier () && + offset.sanitize (c, base, length)); + } + + HBUINT16 platformID; /* Platform ID. */ + HBUINT16 encodingID; /* Platform-specific encoding ID. */ + HBUINT16 languageID; /* Language ID. */ + HBUINT16 nameID; /* Name ID. */ + HBUINT16 length; /* String length (in bytes). */ + NNOffset16To> + offset; /* String offset from start of storage area (in bytes). */ + public: + DEFINE_SIZE_STATIC (12); +}; + +static int +_hb_ot_name_entry_cmp_key (const void *pa, const void *pb, bool exact) +{ + const hb_ot_name_entry_t *a = (const hb_ot_name_entry_t *) pa; + const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb; + + /* Compare by name_id, then language. */ + + if (a->name_id != b->name_id) + return a->name_id - b->name_id; + + if (a->language == b->language) return 0; + if (!a->language) return -1; + if (!b->language) return +1; + + const char *astr = hb_language_to_string (a->language); + const char *bstr = hb_language_to_string (b->language); + + signed c = strcmp (astr, bstr); + + // 'a' is the user request, and 'b' is string in the font. + // If eg. user asks for "en-us" and font has "en", approve. + if (!exact && c && + hb_language_matches (b->language, a->language)) + return 0; + + return c; +} + +static int +_hb_ot_name_entry_cmp (const void *pa, const void *pb) +{ + /* Compare by name_id, then language, then score, then index. */ + + int v = _hb_ot_name_entry_cmp_key (pa, pb, true); + if (v) + return v; + + const hb_ot_name_entry_t *a = (const hb_ot_name_entry_t *) pa; + const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb; + + if (a->entry_score != b->entry_score) + return a->entry_score - b->entry_score; + + if (a->entry_index != b->entry_index) + return a->entry_index - b->entry_index; + + return 0; +} + +struct name +{ + static constexpr hb_tag_t tableTag = HB_OT_TAG_name; + + unsigned int get_size () const + { return min_size + count * nameRecordZ.item_size; } + + template + bool serialize (hb_serialize_context_t *c, + Iterator it, + const void *src_string_pool +#ifdef HB_EXPERIMENTAL_API + , const hb_vector_t& insert_name_records + , const hb_hashmap_t *name_table_overrides +#endif + ) + { + TRACE_SERIALIZE (this); + + if (unlikely (!c->extend_min ((*this)))) return_trace (false); + + unsigned total_count = it.len () +#ifdef HB_EXPERIMENTAL_API + + insert_name_records.length +#endif + ; + this->format = 0; + if (!c->check_assign (this->count, total_count, HB_SERIALIZE_ERROR_INT_OVERFLOW)) + return false; + + NameRecord *name_records = (NameRecord *) hb_calloc (total_count, NameRecord::static_size); + if (unlikely (!name_records)) return_trace (false); + + hb_array_t records (name_records, total_count); + + for (const NameRecord& record : it) + { + hb_memcpy (name_records, &record, NameRecord::static_size); + name_records++; + } + +#ifdef HB_EXPERIMENTAL_API + for (unsigned i = 0; i < insert_name_records.length; i++) + { + const hb_ot_name_record_ids_t& ids = insert_name_records[i]; + NameRecord record; + record.platformID = ids.platform_id; + record.encodingID = ids.encoding_id; + record.languageID = ids.language_id; + record.nameID = ids.name_id; + record.length = 0; // handled in NameRecord copy() + record.offset = 0; + hb_memcpy (name_records, &record, NameRecord::static_size); + name_records++; + } +#endif + + records.qsort (); + + c->copy_all (records, + src_string_pool +#ifdef HB_EXPERIMENTAL_API + , name_table_overrides +#endif + ); + hb_free (records.arrayZ); + + + if (unlikely (c->ran_out_of_room ())) return_trace (false); + + this->stringOffset = c->length (); + + return_trace (true); + } + + bool subset (hb_subset_context_t *c) const + { + auto *name_prime = c->serializer->start_embed (); + +#ifdef HB_EXPERIMENTAL_API + const hb_hashmap_t *name_table_overrides = + &c->plan->name_table_overrides; +#endif + + auto it = + + nameRecordZ.as_array (count) + | hb_filter (c->plan->name_ids, &NameRecord::nameID) + | hb_filter (c->plan->name_languages, &NameRecord::languageID) + | hb_filter ([&] (const NameRecord& namerecord) { + return + (c->plan->flags & HB_SUBSET_FLAGS_NAME_LEGACY) + || namerecord.isUnicode (); + }) +#ifdef HB_EXPERIMENTAL_API + | hb_filter ([&] (const NameRecord& namerecord) { + if (name_table_overrides->is_empty ()) + return true; + hb_ot_name_record_ids_t rec_ids (namerecord.platformID, + namerecord.encodingID, + namerecord.languageID, + namerecord.nameID); + + hb_bytes_t *p; + if (name_table_overrides->has (rec_ids, &p) && + (*p).length == 0) + return false; + return true; + }) +#endif + ; + +#ifdef HB_EXPERIMENTAL_API + hb_hashmap_t retained_name_record_ids; + for (const NameRecord& rec : it) + { + hb_ot_name_record_ids_t rec_ids (rec.platformID, + rec.encodingID, + rec.languageID, + rec.nameID); + retained_name_record_ids.set (rec_ids, 1); + } + + hb_vector_t insert_name_records; + if (!name_table_overrides->is_empty ()) + { + if (unlikely (!insert_name_records.alloc (name_table_overrides->get_population (), true))) + return false; + for (const auto& record_ids : name_table_overrides->keys ()) + { + if (name_table_overrides->get (record_ids).length == 0) + continue; + if (retained_name_record_ids.has (record_ids)) + continue; + insert_name_records.push (record_ids); + } + } +#endif + + return name_prime->serialize (c->serializer, it, + std::addressof (this + stringOffset) +#ifdef HB_EXPERIMENTAL_API + , insert_name_records + , name_table_overrides +#endif + ); + } + + bool sanitize_records (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + const void *string_pool = (this+stringOffset).arrayZ; + return_trace (nameRecordZ.sanitize (c, count, string_pool)); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + hb_barrier () && + likely (format == 0 || format == 1) && + c->check_array (nameRecordZ.arrayZ, count) && + c->check_range (this, stringOffset) && + sanitize_records (c)); + } + + struct accelerator_t + { + accelerator_t (hb_face_t *face) + { + this->table = hb_sanitize_context_t ().reference_table (face); + assert (this->table.get_length () >= this->table->stringOffset); + this->pool = (const char *) (const void *) (this->table+this->table->stringOffset); + this->pool_len = this->table.get_length () - this->table->stringOffset; + const hb_array_t all_names (this->table->nameRecordZ.arrayZ, + this->table->count); + + this->names.alloc (all_names.length, true); + + for (unsigned int i = 0; i < all_names.length; i++) + { + hb_ot_name_entry_t *entry = this->names.push (); + + entry->name_id = all_names[i].nameID; + entry->language = all_names[i].language (face); + entry->entry_score = all_names[i].score (); + entry->entry_index = i; + } + + this->names.qsort (_hb_ot_name_entry_cmp); + /* Walk and pick best only for each name_id,language pair, + * while dropping unsupported encodings. */ + unsigned int j = 0; + for (unsigned int i = 0; i < this->names.length; i++) + { + if (this->names[i].entry_score == UNSUPPORTED || + this->names[i].language == HB_LANGUAGE_INVALID) + continue; + if (i && + this->names[i - 1].name_id == this->names[i].name_id && + this->names[i - 1].language == this->names[i].language) + continue; + this->names[j++] = this->names[i]; + } + this->names.resize (j); + } + ~accelerator_t () + { + this->table.destroy (); + } + + int get_index (hb_ot_name_id_t name_id, + hb_language_t language, + unsigned int *width=nullptr) const + { + const hb_ot_name_entry_t key = {name_id, {0}, language}; + const hb_ot_name_entry_t *entry = hb_bsearch (key, (const hb_ot_name_entry_t *) this->names, + this->names.length, + sizeof (hb_ot_name_entry_t), + _hb_ot_name_entry_cmp_key, + true); + + if (!entry) + { + entry = hb_bsearch (key, (const hb_ot_name_entry_t *) this->names, + this->names.length, + sizeof (hb_ot_name_entry_t), + _hb_ot_name_entry_cmp_key, + false); + } + + if (!entry) + return -1; + + if (width) + *width = entry->entry_score < 10 ? 2 : 1; + + return entry->entry_index; + } + + hb_bytes_t get_name (unsigned int idx) const + { + const hb_array_t all_names (table->nameRecordZ.arrayZ, table->count); + const NameRecord &record = all_names[idx]; + const hb_bytes_t string_pool (pool, pool_len); + return string_pool.sub_array (record.offset, record.length); + } + + private: + const char *pool; + unsigned int pool_len; + public: + hb_blob_ptr_t table; + hb_vector_t names; + }; + + public: + /* We only implement format 0 for now. */ + HBUINT16 format; /* Format selector (=0/1). */ + HBUINT16 count; /* Number of name records. */ + NNOffset16To> + stringOffset; /* Offset to start of string storage (from start of table). */ + UnsizedArrayOf + nameRecordZ; /* The name records where count is the number of records. */ + public: + DEFINE_SIZE_ARRAY (6, nameRecordZ); +}; + +#undef entry_index +#undef entry_score + +struct name_accelerator_t : name::accelerator_t { + name_accelerator_t (hb_face_t *face) : name::accelerator_t (face) {} +}; + +} /* namespace OT */ + + +#endif /* OT_NAME_NAME_HH */ diff --git a/libs/harfbuzz/src/addTable.py b/libs/harfbuzz/src/addTable.py new file mode 100644 index 000000000..103f292dd --- /dev/null +++ b/libs/harfbuzz/src/addTable.py @@ -0,0 +1,16 @@ +import sys +from fontTools.ttLib import TTFont +from fontTools.ttLib.tables.DefaultTable import DefaultTable + +if len(sys.argv) == 1: + print("usage: python addTable.py input.ttf output.ttf Wasm.bin") + sys.exit(1) + +font = TTFont(sys.argv[1]) + +wasm_table = DefaultTable("Wasm") +wasm_table.data = open(sys.argv[3], "rb").read() + +font["Wasm"] = wasm_table + +font.save(sys.argv[2]) diff --git a/libs/harfbuzz/src/check-c-linkage-decls.py b/libs/harfbuzz/src/check-c-linkage-decls.py index fe18eda89..27f5639e7 100644 --- a/libs/harfbuzz/src/check-c-linkage-decls.py +++ b/libs/harfbuzz/src/check-c-linkage-decls.py @@ -14,6 +14,7 @@ def removeprefix(s): HBHEADERS = [os.path.basename (x) for x in os.getenv ('HBHEADERS', '').split ()] or \ [x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith ('.h')] +HBHEADERS = [x for x in HBHEADERS if x.endswith ('.h')] HBSOURCES = [ removeprefix(x) for x in os.getenv ('HBSOURCES', '').split () ] or [ diff --git a/libs/harfbuzz/src/check-libstdc++.py b/libs/harfbuzz/src/check-libstdc++.py index 85b726531..e70d5f80b 100644 --- a/libs/harfbuzz/src/check-libstdc++.py +++ b/libs/harfbuzz/src/check-libstdc++.py @@ -19,7 +19,7 @@ tested = False # harfbuzz-icu links to libstdc++ because icu does. -for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-gobject']: +for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-gobject', 'harfbuzz-cairo']: for suffix in ['so', 'dylib']: so = os.path.join (libs, 'lib%s.%s' % (soname, suffix)) if not os.path.exists (so): continue diff --git a/libs/harfbuzz/src/check-symbols.py b/libs/harfbuzz/src/check-symbols.py index 11ca28dc7..91bf8b067 100644 --- a/libs/harfbuzz/src/check-symbols.py +++ b/libs/harfbuzz/src/check-symbols.py @@ -22,7 +22,7 @@ tested = False stat = 0 -for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-icu', 'harfbuzz-gobject']: +for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-icu', 'harfbuzz-gobject', 'harfbuzz-cairo']: for suffix in ['so', 'dylib']: so = os.path.join (builddir, libs, 'lib%s.%s' % (soname, suffix)) if not os.path.exists (so): continue @@ -31,7 +31,7 @@ symprefix = '_' if suffix == 'dylib' else '' EXPORTED_SYMBOLS = [s.split ()[2] - for s in re.findall (r'^.+ [BCDGIRST] .+$', subprocess.check_output (nm.split() + [so]).decode ('utf-8'), re.MULTILINE) + 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 diff --git a/libs/harfbuzz/src/fix_get_types.py b/libs/harfbuzz/src/fix_get_types.py index 208b9dfcd..64d8ce5a5 100644 --- a/libs/harfbuzz/src/fix_get_types.py +++ b/libs/harfbuzz/src/fix_get_types.py @@ -11,5 +11,5 @@ with open (args.input, 'r') as inp, open (args.output, 'w') as out: for l in inp.readlines (): l = re.sub ('_t_get_type', '_get_type', l) - l = re.sub ('_T \(', ' (', l) + l = re.sub (r'_T \(', ' (', l) out.write (l) diff --git a/libs/harfbuzz/src/gen-def.py b/libs/harfbuzz/src/gen-def.py index e751f524e..6011817bc 100644 --- a/libs/harfbuzz/src/gen-def.py +++ b/libs/harfbuzz/src/gen-def.py @@ -19,10 +19,9 @@ if '--experimental-api' not in sys.argv: # Move these to harfbuzz-sections.txt when got stable experimental_symbols = \ -"""hb_subset_repack_or_fail -hb_subset_input_pin_axis_location -hb_subset_input_pin_axis_to_default -hb_subset_preprocess +"""hb_shape_justify +hb_subset_repack_or_fail +hb_subset_input_override_name_table """.splitlines () symbols = [x for x in symbols if x not in experimental_symbols] symbols = "\n".join (symbols) diff --git a/libs/harfbuzz/src/gen-indic-table.py b/libs/harfbuzz/src/gen-indic-table.py index 0ff3ef4ac..2c8abcca6 100644 --- a/libs/harfbuzz/src/gen-indic-table.py +++ b/libs/harfbuzz/src/gen-indic-table.py @@ -34,6 +34,7 @@ 'Devanagari Extended', 'Myanmar Extended-B', 'Myanmar Extended-A', + 'Myanmar Extended-C', ] files = [open (x, encoding='utf-8') for x in sys.argv[1:]] @@ -95,6 +96,7 @@ 'PLACEHOLDER', 'DOTTEDCIRCLE', 'RS', + 'MPst', 'Repha', 'Ra', 'CM', @@ -168,8 +170,6 @@ 'Vowel' : 'V', 'Vowel_Dependent' : 'M', 'Vowel_Independent' : 'V', - 'Dotted_Circle' : 'DOTTEDCIRCLE', # Ours, not Unicode's - 'Ra' : 'Ra', # Ours, not Unicode's } position_map = { 'Not_Applicable' : 'END', @@ -240,6 +240,9 @@ 0x0953: 'SM', 0x0954: 'SM', + # U+0A40 GURMUKHI VOWEL SIGN II may be preceded by U+0A02 GURMUKHI SIGN BINDI. + 0x0A40: 'MPst', + # The following act like consonants. 0x0A72: 'C', 0x0A73: 'C', @@ -440,7 +443,7 @@ def position_to_category(pos): indic_data[k] = (new_cat, pos, unicode_data[2][k]) # We only expect position for certain types -positioned_categories = ('CM', 'SM', 'RS', 'H', 'M') +positioned_categories = ('CM', 'SM', 'RS', 'H', 'M', 'MPst') for k, (cat, pos, block) in indic_data.items(): if cat not in positioned_categories: pos = 'END' @@ -450,11 +453,12 @@ def position_to_category(pos): # Keep in sync with CONSONANT_FLAGS in the shaper consonant_categories = ('C', 'CS', 'Ra','CM', 'V', 'PLACEHOLDER', 'DOTTEDCIRCLE') +matra_categories = ('M', 'MPst') smvd_categories = ('SM', 'VD', 'A', 'Symbol') for k, (cat, pos, block) in indic_data.items(): if cat in consonant_categories: pos = 'BASE_C' - elif cat == 'M': + elif cat in matra_categories: if block.startswith('Khmer') or block.startswith('Myanmar'): cat = position_to_category(pos) else: @@ -634,7 +638,7 @@ def print_block (block, start, end, data): end = (end-1)//8*8 + 7 if start != last + 1: - if start - last <= 1+16*3: + if start - last <= 1+16*2: print_block (None, last+1, start-1, indic_data) else: if last >= 0: @@ -691,6 +695,6 @@ def print_block (block, start, end, data): print () print ("/* == End of generated table == */") -# Maintain at least 30% occupancy in the table */ -if occupancy < 30: +# Maintain at least 50% occupancy in the table */ +if occupancy < 50: raise Exception ("Table too sparse, please investigate: ", occupancy) diff --git a/libs/harfbuzz/src/gen-tag-table.py b/libs/harfbuzz/src/gen-tag-table.py index 7e15c08c5..9bb8f917a 100644 --- a/libs/harfbuzz/src/gen-tag-table.py +++ b/libs/harfbuzz/src/gen-tag-table.py @@ -345,14 +345,18 @@ def __init__ (self): self.from_bcp_47_uninherited = None # Whether the parser is in a element self._td = False - # Whether the parser is after a
element within the current element - self._br = False + # Whether the parser ignores the rest of the current element + self._disengaged = False # The text of the elements of the current element. self._current_tr = [] def handle_starttag (self, tag, attrs): - if tag == 'br': - self._br = True + if tag == 'a': + if self._current_tr and not self._disengaged: + self._current_tr[-1] = '' + self._disengaged = True + elif tag == 'br': + self._disengaged = True elif tag == 'meta': for attr, value in attrs: if attr == 'name' and value == 'updated_at': @@ -362,12 +366,13 @@ def handle_starttag (self, tag, attrs): self._td = True self._current_tr.append ('') elif tag == 'tr': - self._br = False + self._disengaged = False self._current_tr = [] def handle_endtag (self, tag): if tag == 'td': self._td = False + self._disengaged = False elif tag == 'tr' and self._current_tr: expect (2 <= len (self._current_tr) <= 3) name = self._current_tr[0].strip () @@ -387,7 +392,7 @@ def handle_endtag (self, tag): self.ranks[tag] = rank def handle_data (self, data): - if self._td and not self._br: + if self._td and not self._disengaged: self._current_tr[-1] += data def handle_charref (self, name): @@ -584,7 +589,7 @@ def parse (self, filename): self.grandfathered.add (subtag.lower ()) elif line.startswith ('Description: '): description = line.split (' ', 1)[1].replace (' (individual language)', '') - description = re.sub (' (\(family\)|\((individual |macro)language\)|languages)$', '', + description = re.sub (r' (\(family\)|\((individual |macro)language\)|languages)$', '', description) if subtag in self.names: self.names[subtag] += '\n' + description @@ -699,8 +704,6 @@ def get_name (self, lt): ot.remove_language_ot ('PGR') ot.add_language ('el-polyton', 'PGR') -bcp_47.macrolanguages['et'] = {'ekk'} - bcp_47.names['flm'] = 'Falam Chin' bcp_47.scopes['flm'] = ' (retired code)' bcp_47.macrolanguages['flm'] = {'cfm'} @@ -711,7 +714,6 @@ def get_name (self, lt): ot.add_language ('und-fonnapa', 'APPH') -ot.remove_language_ot ('IRT') ot.add_language ('ga-Latg', 'IRT') ot.add_language ('hy-arevmda', 'HYE') @@ -719,10 +721,6 @@ def get_name (self, lt): ot.remove_language_ot ('KGE') ot.add_language ('und-Geok', 'KGE') -bcp_47.macrolanguages['id'] = {'in'} - -bcp_47.macrolanguages['ijo'] = {'ijc'} - ot.add_language ('kht', 'KHN') ot.names['KHN'] = ot.names['KHT'] + ' (Microsoft fonts)' ot.ranks['KHN'] = ot.ranks['KHT'] + 1 @@ -809,8 +807,6 @@ def get_name (self, lt): ot.add_language ('yue', 'ZHH') ot.add_language ('yue-Hans', 'ZHS') -bcp_47.macrolanguages['zom'] = {'yos'} - def rank_delta (bcp_47, ot): """Return a delta to apply to a BCP 47 tag's rank. @@ -1127,9 +1123,10 @@ def print_subtag_matches (subtag, string, new_line): print (' * @tag: A language tag.') print (' *') print (' * Converts @tag to a BCP 47 language tag if it is ambiguous (it corresponds to') -print (' * many language tags) and the best tag is not the alphabetically first, or if') -print (' * the best tag consists of multiple subtags, or if the best tag does not appear') -print (' * in #ot_languages.') +print (' * many language tags) and the best tag is not the first (sorted alphabetically,') +print (' * with two-letter tags having priority over all three-letter tags), or if the') +print (' * best tag consists of multiple subtags, or if the best tag does not appear in') +print (' * #ot_languages2 or #ot_languages3.') print (' *') print (' * Return value: The #hb_language_t corresponding to the BCP 47 language tag,') print (' * or #HB_LANGUAGE_INVALID if @tag is not ambiguous.') @@ -1170,7 +1167,8 @@ def verify_disambiguation_dict (): if '-' in primary_tags[0]: disambiguation[ot_tag] = primary_tags[0] else: - first_tag = sorted (t for t in bcp_47_tags if t not in bcp_47.grandfathered and ot_tag in ot.from_bcp_47.get (t))[0] + first_tag = sorted ((t for t in bcp_47_tags if t not in bcp_47.grandfathered and ot_tag in ot.from_bcp_47.get (t)), + key=lambda t: (len (t), t))[0] if primary_tags[0] != first_tag: disambiguation[ot_tag] = primary_tags[0] elif len (primary_tags) == 0: @@ -1186,14 +1184,20 @@ def verify_disambiguation_dict (): if len (macrolanguages) != 1: macrolanguages = list (t for t in primary_tags if 'retired code' not in bcp_47.scopes.get (t, '')) if len (macrolanguages) != 1: - expect (ot_tag in disambiguation, 'ambiguous OT tag: %s %s' % (ot_tag, str (macrolanguages))) + macrolanguages = list (t for t in primary_tags if t.lower () == ISO_639_3_TO_1.get (ot_tag.lower (), ot_tag.lower ())) + if len (macrolanguages) != 1: + macrolanguages = list (t for t in primary_tags if '-' not in t) + if len (macrolanguages) != 1: + expect (ot_tag in disambiguation, 'ambiguous OT tag: %s %s' % (ot_tag, sorted (primary_tags))) expect (disambiguation[ot_tag] in bcp_47_tags, '%s is not a valid disambiguation for %s' % (disambiguation[ot_tag], ot_tag)) elif ot_tag not in disambiguation: disambiguation[ot_tag] = macrolanguages[0] - different_bcp_47_tags = sorted (t for t in bcp_47_tags if not same_tag (t, ot.from_bcp_47.get (t))) - if different_bcp_47_tags and disambiguation[ot_tag] == different_bcp_47_tags[0] and '-' not in disambiguation[ot_tag]: - del disambiguation[ot_tag] + if '-' not in disambiguation[ot_tag]: + different_bcp_47_tags = sorted ((t for t in bcp_47_tags if not same_tag (t, ot.from_bcp_47.get (t))), + key=lambda t: (len (t), t)) + if different_bcp_47_tags and disambiguation[ot_tag] == different_bcp_47_tags[0]: + del disambiguation[ot_tag] for ot_tag in disambiguation.keys (): expect (ot_tag in ot.to_bcp_47, 'unknown OT tag: %s' % ot_tag) diff --git a/libs/harfbuzz/src/gen-ucd-table.py b/libs/harfbuzz/src/gen-ucd-table.py index f4c099f86..d85ae4faa 100644 --- a/libs/harfbuzz/src/gen-ucd-table.py +++ b/libs/harfbuzz/src/gen-ucd-table.py @@ -25,14 +25,28 @@ logging.info('Preparing data tables...') + +# This is how the data is encoded: +# +# General_Category (gc), Canonical_Combining_Class (ccc), +# and Script (sc) are encoded as integers. +# +# Mirroring character (bmg) is encoded as difference from +# the original character. +# +# Composition & Decomposition (dm) are encoded elaborately, +# as discussed below. + gc = [u['gc'] for u in ucd] ccc = [int(u['ccc']) for u in ucd] bmg = [int(v, 16) - int(u) if v else 0 for u,v in enumerate(u['bmg'] for u in ucd)] -#gc_ccc_non0 = set((cat,klass) for cat,klass in zip(gc,ccc) if klass) -#gc_bmg_non0 = set((cat,mirr) for cat,mirr in zip(gc, bmg) if mirr) - sc = [u['sc'] for u in ucd] + +# Prepare Compose / Decompose data +# +# This code is very dense. See hb_ucd_compose() / hb_ucd_decompose() for the logic. + dm = {i:tuple(int(v, 16) for v in u['dm'].split()) for i,u in enumerate(ucd) if u['dm'] != '#' and u['dt'] == 'can' and not (0xAC00 <= i < 0xAC00+11172)} ce = {i for i,u in enumerate(ucd) if u['Comp_Ex'] == 'Y'} @@ -63,6 +77,9 @@ dm_order.update(dm1_order) dm_order.update(dm2_order) + +# Prepare General_Category / Script mapping arrays + gc_order = dict() for i,v in enumerate(('Cc', 'Cf', 'Cn', 'Co', 'Cs', 'Ll', 'Lm', 'Lo', 'Lt', 'Lu', 'Mc', 'Me', 'Mn', 'Nd', 'Nl', 'No', 'Pc', 'Pd', 'Pe', 'Pf', @@ -83,10 +100,18 @@ sc_order[i] = tag sc_array.append(name) -DEFAULT = 3 -COMPACT = 5 -SLOPPY = 9 +# Write out main data + +DEFAULT = 'DEFAULT' +COMPACT = 'COMPACT' +SLOPPY = 'SLOPPY' + +compression_level = { + DEFAULT: 5, + COMPACT: 9, + SLOPPY: 9, +} logging.info('Generating output...') print("/* == Start of generated table == */") @@ -104,6 +129,9 @@ print('#include "hb.hh"') print() + +# Write mapping data + code = packTab.Code('_hb_ucd') sc_array, _ = code.addArray('hb_script_t', 'sc_map', sc_array) dm1_p0_array, _ = code.addArray('uint16_t', 'dm1_p0_map', dm1_p0_array) @@ -120,18 +148,24 @@ ('dm', dm, None, dm_order), ] -for compression in (DEFAULT, COMPACT, SLOPPY): + +# Write main data + +for step in (DEFAULT, COMPACT, SLOPPY): + compression = compression_level[step] logging.info(' Compression=%d:' % compression) print() - if compression == DEFAULT: + if step == DEFAULT: print('#ifndef HB_OPTIMIZE_SIZE') - elif compression == COMPACT: + elif step == COMPACT: print('#elif !defined(HB_NO_UCD_UNASSIGNED)') - else: + elif step == SLOPPY: print('#else') + else: + assert False print() - if compression == SLOPPY: + if step == SLOPPY: for i in range(len(gc)): if (i % 128) and gc[i] == 'Cn': gc[i] = gc[i - 1] @@ -157,6 +191,7 @@ print() + print('#endif') print() diff --git a/libs/harfbuzz/src/gen-use-table.py b/libs/harfbuzz/src/gen-use-table.py index 0600a3388..4e8680650 100644 --- a/libs/harfbuzz/src/gen-use-table.py +++ b/libs/harfbuzz/src/gen-use-table.py @@ -15,6 +15,10 @@ * ms-use/IndicPositionalCategory-Additional.txt """ +import logging +logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO) + + import sys if len (sys.argv) != 10: @@ -105,6 +109,7 @@ 'Nukta', 'Virama', 'Pure_Killer', + 'Reordering_Killer', 'Invisible_Stacker', 'Vowel_Independent', 'Vowel_Dependent', @@ -137,6 +142,10 @@ 'Symbol_Modifier', 'Hieroglyph', 'Hieroglyph_Joiner', + 'Hieroglyph_Mark_Begin', + 'Hieroglyph_Mark_End', + 'Hieroglyph_Mirror', + 'Hieroglyph_Modifier', 'Hieroglyph_Segment_Begin', 'Hieroglyph_Segment_End', # Indic_Positional_Category @@ -231,10 +240,14 @@ def is_HIEROGLYPH(U, UISC, UDI, UGC, AJT): return UISC == Hieroglyph def is_HIEROGLYPH_JOINER(U, UISC, UDI, UGC, AJT): return UISC == Hieroglyph_Joiner +def is_HIEROGLYPH_MIRROR(U, UISC, UDI, UGC, AJT): + return UISC == Hieroglyph_Mirror +def is_HIEROGLYPH_MOD(U, UISC, UDI, UGC, AJT): + return UISC == Hieroglyph_Modifier def is_HIEROGLYPH_SEGMENT_BEGIN(U, UISC, UDI, UGC, AJT): - return UISC == Hieroglyph_Segment_Begin + return UISC in [Hieroglyph_Mark_Begin, Hieroglyph_Segment_Begin] def is_HIEROGLYPH_SEGMENT_END(U, UISC, UDI, UGC, AJT): - return UISC == Hieroglyph_Segment_End + return UISC in [Hieroglyph_Mark_End, Hieroglyph_Segment_End] def is_INVISIBLE_STACKER(U, UISC, UDI, UGC, AJT): # Split off of HALANT return (UISC == Invisible_Stacker @@ -251,6 +264,8 @@ def is_OTHER(U, UISC, UDI, UGC, AJT): and not is_SYM_MOD(U, UISC, UDI, UGC, AJT) and not is_Word_Joiner(U, UISC, UDI, UGC, AJT) ) +def is_REORDERING_KILLER(U, UISC, UDI, UGC, AJT): + return UISC == Reordering_Killer def is_REPHA(U, UISC, UDI, UGC, AJT): return UISC in [Consonant_Preceding_Repha, Consonant_Prefixed] def is_SAKOT(U, UISC, UDI, UGC, AJT): @@ -287,11 +302,14 @@ def is_Word_Joiner(U, UISC, UDI, UGC, AJT): 'HN': is_HALANT_NUM, 'IS': is_INVISIBLE_STACKER, 'G': is_HIEROGLYPH, + 'HM': is_HIEROGLYPH_MOD, + 'HR': is_HIEROGLYPH_MIRROR, 'J': is_HIEROGLYPH_JOINER, 'SB': is_HIEROGLYPH_SEGMENT_BEGIN, 'SE': is_HIEROGLYPH_SEGMENT_END, 'ZWNJ': is_ZWNJ, 'O': is_OTHER, + 'RK': is_REORDERING_KILLER, 'R': is_REPHA, 'Sk': is_SAKOT, 'SM': is_SYM_MOD, @@ -333,6 +351,8 @@ def is_Word_Joiner(U, UISC, UDI, UGC, AJT): 'Blw': [Bottom], }, 'H': None, + 'HM': None, + 'HR': None, 'HVM': None, 'IS': None, 'B': None, @@ -342,6 +362,7 @@ def is_Word_Joiner(U, UISC, UDI, UGC, AJT): 'Pst': [Not_Applicable], }, 'R': None, + 'RK': None, 'SUB': None, } @@ -373,7 +394,11 @@ def map_to_use(data): # and https://github.com/harfbuzz/harfbuzz/issues/1631 if U in [0x11302, 0x11303, 0x114C1]: UIPC = Top - assert (UIPC in [Not_Applicable, Visual_Order_Left] or U == 0x0F7F or + # TODO: https://github.com/microsoft/font-tools/issues/17#issuecomment-2346952091 + if U == 0x113CF: UIPC = Bottom + + assert (UIPC in [Not_Applicable, Visual_Order_Left] or + U in {0x0F7F, 0x11A3A} or USE in use_positions), "%s %s %s %s %s %s %s" % (hex(U), UIPC, USE, UISC, UDI, UGC, AJT) pos_mapping = use_positions.get(USE, None) @@ -465,10 +490,29 @@ def print_block (block, start, end, use_data): import packTab data = {u:v[0] for u,v in use_data.items()} -code = packTab.Code('hb_use') -sol = packTab.pack_table(data, compression=5, default='O') -sol.genCode(code, f'get_category') -code.print_c(linkage='static inline') + +DEFAULT = 5 +COMPACT = 9 +for compression in (DEFAULT, COMPACT): + + logging.info(' Compression=%d:' % compression) + print() + if compression == DEFAULT: + print('#ifndef HB_OPTIMIZE_SIZE') + elif compression == COMPACT: + print('#else') + else: + assert False + print() + + code = packTab.Code('hb_use') + sol = packTab.pack_table(data, compression=compression, default='O') + logging.info(' FullCost=%d' % (sol.fullCost)) + sol.genCode(code, f'get_category') + code.print_c(linkage='static inline') + print () + +print('#endif') print () for k in sorted(use_mapping.keys()): diff --git a/libs/harfbuzz/src/graph/classdef-graph.hh b/libs/harfbuzz/src/graph/classdef-graph.hh index 0bda76ac2..da6378820 100644 --- a/libs/harfbuzz/src/graph/classdef-graph.hh +++ b/libs/harfbuzz/src/graph/classdef-graph.hh @@ -39,6 +39,7 @@ struct ClassDefFormat1 : public OT::ClassDefFormat1_3 int64_t vertex_len = vertex.obj.tail - vertex.obj.head; constexpr unsigned min_size = OT::ClassDefFormat1_3::min_size; if (vertex_len < min_size) return false; + hb_barrier (); return vertex_len >= min_size + classValue.get_size () - classValue.len.get_size (); } }; @@ -50,6 +51,7 @@ struct ClassDefFormat2 : public OT::ClassDefFormat2_4 int64_t vertex_len = vertex.obj.tail - vertex.obj.head; constexpr unsigned min_size = OT::ClassDefFormat2_4::min_size; if (vertex_len < min_size) return false; + hb_barrier (); return vertex_len >= min_size + rangeRecord.get_size () - rangeRecord.len.get_size (); } }; @@ -72,7 +74,7 @@ struct ClassDef : public OT::ClassDef class_def_link->width = SmallTypes::size; class_def_link->objidx = class_def_prime_id; class_def_link->position = link_position; - class_def_prime_vertex.parents.push (parent_id); + class_def_prime_vertex.add_parent (parent_id); return true; } @@ -94,7 +96,13 @@ struct ClassDef : public OT::ClassDef } hb_bytes_t class_def_copy = serializer.copy_bytes (); - c.add_buffer ((char *) class_def_copy.arrayZ); // Give ownership to the context, it will cleanup the buffer. + if (!class_def_copy.arrayZ) return false; + // Give ownership to the context, it will cleanup the buffer. + if (!c.add_buffer ((char *) class_def_copy.arrayZ)) + { + hb_free ((char *) class_def_copy.arrayZ); + return false; + } auto& obj = c.graph.vertices_[dest_obj].obj; obj.head = (char *) class_def_copy.arrayZ; @@ -108,11 +116,12 @@ struct ClassDef : public OT::ClassDef { int64_t vertex_len = vertex.obj.tail - vertex.obj.head; if (vertex_len < OT::ClassDef::min_size) return false; + hb_barrier (); switch (u.format) { case 1: return ((ClassDefFormat1*)this)->sanitize (vertex); case 2: return ((ClassDefFormat2*)this)->sanitize (vertex); -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K // Not currently supported case 3: case 4: @@ -125,20 +134,23 @@ struct ClassDef : public OT::ClassDef struct class_def_size_estimator_t { + // TODO(garretrieger): update to support beyond64k coverage/classdef tables. + constexpr static unsigned class_def_format1_base_size = 6; + constexpr static unsigned class_def_format2_base_size = 4; + constexpr static unsigned coverage_base_size = 4; + constexpr static unsigned bytes_per_range = 6; + constexpr static unsigned bytes_per_glyph = 2; + template class_def_size_estimator_t (It glyph_and_class) - : gids_consecutive (true), num_ranges_per_class (), glyphs_per_class () + : num_ranges_per_class (), glyphs_per_class () { - unsigned last_gid = (unsigned) -1; + reset(); for (auto p : + glyph_and_class) { unsigned gid = p.first; unsigned klass = p.second; - if (last_gid != (unsigned) -1 && gid != last_gid + 1) - gids_consecutive = false; - last_gid = gid; - hb_set_t* glyphs; if (glyphs_per_class.has (klass, &glyphs) && glyphs) { glyphs->add (gid); @@ -168,28 +180,54 @@ struct class_def_size_estimator_t } } - // Incremental increase in the Coverage and ClassDef table size - // (worst case) if all glyphs associated with 'klass' were added. - unsigned incremental_coverage_size (unsigned klass) const + void reset() { + class_def_1_size = class_def_format1_base_size; + class_def_2_size = class_def_format2_base_size; + included_glyphs.clear(); + included_classes.clear(); + } + + // Compute the size of coverage for all glyphs added via 'add_class_def_size'. + unsigned coverage_size () const { - // Coverage takes 2 bytes per glyph worst case, - return 2 * glyphs_per_class.get (klass).get_population (); + unsigned format1_size = coverage_base_size + bytes_per_glyph * included_glyphs.get_population(); + unsigned format2_size = coverage_base_size + bytes_per_range * num_glyph_ranges(); + return hb_min(format1_size, format2_size); } - // Incremental increase in the Coverage and ClassDef table size - // (worst case) if all glyphs associated with 'klass' were added. - unsigned incremental_class_def_size (unsigned klass) const + // Compute the new size of the ClassDef table if all glyphs associated with 'klass' were added. + unsigned add_class_def_size (unsigned klass) { - // ClassDef takes 6 bytes per range - unsigned class_def_2_size = 6 * num_ranges_per_class.get (klass); - if (gids_consecutive) - { - // ClassDef1 takes 2 bytes per glyph, but only can be used - // when gids are consecutive. - return hb_min (2 * glyphs_per_class.get (klass).get_population (), class_def_2_size); + if (!included_classes.has(klass)) { + hb_set_t* glyphs = nullptr; + if (glyphs_per_class.has(klass, &glyphs)) { + included_glyphs.union_(*glyphs); + } + + class_def_1_size = class_def_format1_base_size; + if (!included_glyphs.is_empty()) { + unsigned min_glyph = included_glyphs.get_min(); + unsigned max_glyph = included_glyphs.get_max(); + class_def_1_size += bytes_per_glyph * (max_glyph - min_glyph + 1); + } + + class_def_2_size += bytes_per_range * num_ranges_per_class.get (klass); + + included_classes.add(klass); } - return class_def_2_size; + return hb_min (class_def_1_size, class_def_2_size); + } + + unsigned num_glyph_ranges() const { + hb_codepoint_t start = HB_SET_VALUE_INVALID; + hb_codepoint_t end = HB_SET_VALUE_INVALID; + + unsigned count = 0; + while (included_glyphs.next_range (&start, &end)) { + count++; + } + return count; } bool in_error () @@ -205,9 +243,12 @@ struct class_def_size_estimator_t } private: - bool gids_consecutive; hb_hashmap_t num_ranges_per_class; hb_hashmap_t glyphs_per_class; + hb_set_t included_classes; + hb_set_t included_glyphs; + unsigned class_def_1_size; + unsigned class_def_2_size; }; diff --git a/libs/harfbuzz/src/graph/coverage-graph.hh b/libs/harfbuzz/src/graph/coverage-graph.hh index 3c1022f09..61ca063e3 100644 --- a/libs/harfbuzz/src/graph/coverage-graph.hh +++ b/libs/harfbuzz/src/graph/coverage-graph.hh @@ -39,6 +39,7 @@ struct CoverageFormat1 : public OT::Layout::Common::CoverageFormat1_3::min_size; if (vertex_len < min_size) return false; + hb_barrier (); return vertex_len >= min_size + glyphArray.get_size () - glyphArray.len.get_size (); } }; @@ -50,6 +51,7 @@ struct CoverageFormat2 : public OT::Layout::Common::CoverageFormat2_4::min_size; if (vertex_len < min_size) return false; + hb_barrier (); return vertex_len >= min_size + rangeRecord.get_size () - rangeRecord.len.get_size (); } }; @@ -96,7 +98,7 @@ struct Coverage : public OT::Layout::Common::Coverage coverage_link->width = SmallTypes::size; coverage_link->objidx = coverage_prime_id; coverage_link->position = link_position; - coverage_prime_vertex.parents.push (parent_id); + coverage_prime_vertex.add_parent (parent_id); return (Coverage*) coverage_prime_vertex.obj.head; } @@ -118,7 +120,13 @@ struct Coverage : public OT::Layout::Common::Coverage } hb_bytes_t coverage_copy = serializer.copy_bytes (); - c.add_buffer ((char *) coverage_copy.arrayZ); // Give ownership to the context, it will cleanup the buffer. + if (!coverage_copy.arrayZ) return false; + // Give ownership to the context, it will cleanup the buffer. + if (!c.add_buffer ((char *) coverage_copy.arrayZ)) + { + hb_free ((char *) coverage_copy.arrayZ); + return false; + } auto& obj = c.graph.vertices_[dest_obj].obj; obj.head = (char *) coverage_copy.arrayZ; @@ -132,11 +140,12 @@ struct Coverage : public OT::Layout::Common::Coverage { int64_t vertex_len = vertex.obj.tail - vertex.obj.head; if (vertex_len < OT::Layout::Common::Coverage::min_size) return false; + hb_barrier (); switch (u.format) { case 1: return ((CoverageFormat1*)this)->sanitize (vertex); case 2: return ((CoverageFormat2*)this)->sanitize (vertex); -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K // Not currently supported case 3: case 4: diff --git a/libs/harfbuzz/src/graph/graph.hh b/libs/harfbuzz/src/graph/graph.hh index 79c7e690a..b24507ece 100644 --- a/libs/harfbuzz/src/graph/graph.hh +++ b/libs/harfbuzz/src/graph/graph.hh @@ -43,11 +43,71 @@ struct graph_t { hb_serialize_context_t::object_t obj; int64_t distance = 0 ; - int64_t space = 0 ; - hb_vector_t parents; + unsigned space = 0 ; unsigned start = 0; unsigned end = 0; unsigned priority = 0; + private: + unsigned incoming_edges_ = 0; + unsigned single_parent = (unsigned) -1; + hb_hashmap_t parents; + public: + + auto parents_iter () const HB_AUTO_RETURN + ( + hb_concat ( + hb_iter (&single_parent, single_parent != (unsigned) -1), + parents.keys_ref () + ) + ) + + bool in_error () const + { + return parents.in_error (); + } + + bool link_positions_valid (unsigned num_objects, bool removed_nil) + { + hb_set_t assigned_bytes; + for (const auto& l : obj.real_links) + { + if (l.objidx >= num_objects + || (removed_nil && !l.objidx)) + { + DEBUG_MSG (SUBSET_REPACK, nullptr, + "Invalid graph. Invalid object index."); + return false; + } + + unsigned start = l.position; + unsigned end = start + l.width - 1; + + if (unlikely (l.width < 2 || l.width > 4)) + { + DEBUG_MSG (SUBSET_REPACK, nullptr, + "Invalid graph. Invalid link width."); + return false; + } + + if (unlikely (end >= table_size ())) + { + DEBUG_MSG (SUBSET_REPACK, nullptr, + "Invalid graph. Link position is out of bounds."); + return false; + } + + if (unlikely (assigned_bytes.intersects (start, end))) + { + DEBUG_MSG (SUBSET_REPACK, nullptr, + "Invalid graph. Found offsets whose positions overlap."); + return false; + } + + assigned_bytes.add_range (start, end); + } + + return !assigned_bytes.in_error (); + } void normalize () { @@ -79,7 +139,7 @@ struct graph_t while (a || b) { DEBUG_MSG (SUBSET_REPACK, nullptr, - " 0x%x %s 0x%x", *a, (*a == *b) ? "==" : "!=", *b); + " 0x%x %s 0x%x", (unsigned) *a, (*a == *b) ? "==" : "!=", (unsigned) *b); a++; b++; } @@ -99,7 +159,9 @@ struct graph_t hb_swap (a.obj, b.obj); hb_swap (a.distance, b.distance); hb_swap (a.space, b.space); + hb_swap (a.single_parent, b.single_parent); hb_swap (a.parents, b.parents); + hb_swap (a.incoming_edges_, b.incoming_edges_); hb_swap (a.start, b.start); hb_swap (a.end, b.end); hb_swap (a.priority, b.priority); @@ -110,6 +172,7 @@ struct graph_t { hb_hashmap_t result; + result.alloc (obj.real_links.length); for (const auto& l : obj.real_links) { result.set (l.position, l.objidx); } @@ -119,27 +182,92 @@ struct graph_t bool is_shared () const { - return parents.length > 1; + return parents.get_population () > 1; } unsigned incoming_edges () const { - return parents.length; + if (HB_DEBUG_SUBSET_REPACK) + { + assert (incoming_edges_ == (single_parent != (unsigned) -1) + + (parents.values_ref () | hb_reduce (hb_add, 0))); + } + return incoming_edges_; + } + + unsigned incoming_edges_from_parent (unsigned parent_index) const { + if (single_parent != (unsigned) -1) { + return single_parent == parent_index ? 1 : 0; + } + + unsigned* count; + return parents.has(parent_index, &count) ? *count : 0; + } + + void reset_parents () + { + incoming_edges_ = 0; + single_parent = (unsigned) -1; + parents.reset (); + } + + void add_parent (unsigned parent_index) + { + assert (parent_index != (unsigned) -1); + if (incoming_edges_ == 0) + { + single_parent = parent_index; + incoming_edges_ = 1; + return; + } + else if (single_parent != (unsigned) -1) + { + assert (incoming_edges_ == 1); + if (!parents.set (single_parent, 1)) + return; + single_parent = (unsigned) -1; + } + + unsigned *v; + if (parents.has (parent_index, &v)) + { + (*v)++; + incoming_edges_++; + } + else if (parents.set (parent_index, 1)) + incoming_edges_++; } void remove_parent (unsigned parent_index) { - for (unsigned i = 0; i < parents.length; i++) + if (parent_index == single_parent) + { + single_parent = (unsigned) -1; + incoming_edges_--; + return; + } + + unsigned *v; + if (parents.has (parent_index, &v)) { - if (parents[i] != parent_index) continue; - parents.remove (i); - break; + incoming_edges_--; + if (*v > 1) + (*v)--; + else + parents.del (parent_index); + + if (incoming_edges_ == 1) + { + single_parent = *parents.keys (); + parents.reset (); + } } } void remove_real_link (unsigned child_index, const void* offset) { - for (unsigned i = 0; i < obj.real_links.length; i++) + unsigned count = obj.real_links.length; + for (unsigned i = 0; i < count; i++) { auto& link = obj.real_links.arrayZ[i]; if (link.objidx != child_index) @@ -148,23 +276,58 @@ struct graph_t if ((obj.head + link.position) != offset) continue; - obj.real_links.remove (i); + obj.real_links.remove_unordered (i); return; } } - void remap_parents (const hb_vector_t& id_map) + bool remap_parents (const hb_vector_t& id_map) { - for (unsigned i = 0; i < parents.length; i++) - parents[i] = id_map[parents[i]]; + if (single_parent != (unsigned) -1) + { + assert (single_parent < id_map.length); + single_parent = id_map[single_parent]; + return true; + } + + hb_hashmap_t new_parents; + new_parents.alloc (parents.get_population ()); + for (auto _ : parents) + { + assert (_.first < id_map.length); + assert (!new_parents.has (id_map[_.first])); + new_parents.set (id_map[_.first], _.second); + } + + if (parents.in_error() || new_parents.in_error ()) + return false; + + parents = std::move (new_parents); + return true; } void remap_parent (unsigned old_index, unsigned new_index) { - for (unsigned i = 0; i < parents.length; i++) + if (single_parent != (unsigned) -1) { - if (parents[i] == old_index) - parents[i] = new_index; + if (single_parent == old_index) + single_parent = new_index; + return; + } + + const unsigned *pv; + if (parents.has (old_index, &pv)) + { + unsigned v = *pv; + if (!parents.set (new_index, v)) + incoming_edges_ -= v; + parents.del (old_index); + + if (incoming_edges_ == 1) + { + single_parent = *parents.keys (); + parents.reset (); + } } } @@ -180,6 +343,16 @@ struct graph_t return true; } + bool give_max_priority () + { + bool result = false; + while (!has_max_priority()) { + result = true; + priority++; + } + return result; + } + bool has_max_priority () const { return priority >= 3; } @@ -195,7 +368,7 @@ struct graph_t // it's parent where possible. int64_t modified_distance = - hb_min (hb_max(distance + distance_modifier (), 0), 0x7FFFFFFFFFF); + hb_clamp (distance + distance_modifier (), (int64_t) 0, 0x7FFFFFFFFFF); if (has_max_priority ()) { modified_distance = 0; } @@ -284,13 +457,12 @@ struct graph_t bool removed_nil = false; vertices_.alloc (objects.length); vertices_scratch_.alloc (objects.length); - for (unsigned i = 0; i < objects.length; i++) + unsigned count = objects.length; + for (unsigned i = 0; i < count; i++) { - // TODO(grieger): check all links point to valid objects. - // If this graph came from a serialization buffer object 0 is the // nil object. We don't need it for our purposes here so drop it. - if (i == 0 && !objects[i]) + if (i == 0 && !objects.arrayZ[i]) { removed_nil = true; continue; @@ -298,7 +470,10 @@ struct graph_t vertex_t* v = vertices_.push (); if (check_success (!vertices_.in_error ())) - v->obj = *objects[i]; + v->obj = *objects.arrayZ[i]; + + check_success (v->link_positions_valid (count, removed_nil)); + if (!removed_nil) continue; // Fix indices to account for removed nil object. for (auto& l : v->obj.all_links_writer ()) { @@ -309,7 +484,6 @@ struct graph_t ~graph_t () { - vertices_.fini (); for (char* b : buffers) hb_free (b); } @@ -319,6 +493,18 @@ struct graph_t return root ().equals (other.root (), *this, other, 0); } + void print () const { + for (int i = vertices_.length - 1; i >= 0; i--) + { + const auto& v = vertices_[i]; + printf("%d: %u [", i, (unsigned int)v.table_size()); + for (const auto &l : v.obj.real_links) { + printf("%u, ", l.objidx); + } + printf("]\n"); + } + } + // Sorts links of all objects in a consistent manner and zeroes all offsets. void normalize () { @@ -351,9 +537,10 @@ struct graph_t return vertices_[i].obj; } - void add_buffer (char* buffer) + bool add_buffer (char* buffer) { buffers.push (buffer); + return !buffers.in_error (); } /* @@ -369,7 +556,7 @@ struct graph_t link->width = 2; link->objidx = child_id; link->position = (char*) offset - (char*) v.obj.head; - vertices_[child_id].parents.push (parent_id); + vertices_[child_id].add_parent (parent_id); } /* @@ -398,7 +585,8 @@ struct graph_t update_distances (); - hb_priority_queue_t queue; + hb_priority_queue_t queue; + queue.alloc (vertices_.length); hb_vector_t &sorted_graph = vertices_scratch_; if (unlikely (!check_success (sorted_graph.resize (vertices_.length)))) return; hb_vector_t id_map; @@ -415,9 +603,16 @@ struct graph_t { unsigned next_id = queue.pop_minimum().second; - hb_swap (sorted_graph[new_id], vertices_[next_id]); + sorted_graph[new_id] = std::move (vertices_[next_id]); const vertex_t& next = sorted_graph[new_id]; + if (unlikely (!check_success(new_id >= 0))) { + // We are out of ids. Which means we've visited a node more than once. + // This graph contains a cycle which is not allowed. + DEBUG_MSG (SUBSET_REPACK, nullptr, "Invalid graph. Contains cycle."); + return; + } + id_map[next_id] = new_id--; for (const auto& link : next.obj.all_links ()) { @@ -436,8 +631,8 @@ struct graph_t check_success (!queue.in_error ()); check_success (!sorted_graph.in_error ()); - remap_all_obj_indices (id_map, &sorted_graph); - hb_swap (vertices_, sorted_graph); + check_success (remap_all_obj_indices (id_map, &sorted_graph)); + vertices_ = std::move (sorted_graph); if (!check_success (new_id == -1)) print_orphaned_nodes (); @@ -527,8 +722,8 @@ struct graph_t const auto& node = object (node_idx); if (offset < node.head || offset >= node.tail) return -1; - unsigned length = node.real_links.length; - for (unsigned i = 0; i < length; i++) + unsigned count = node.real_links.length; + for (unsigned i = 0; i < count; i++) { // Use direct access for increased performance, this is a hot method. const auto& link = node.real_links.arrayZ[i]; @@ -548,7 +743,7 @@ struct graph_t { unsigned child_idx = index_for_offset (node_idx, offset); auto& child = vertices_[child_idx]; - for (unsigned p : child.parents) + for (unsigned p : child.parents_iter ()) { if (p != node_idx) { return duplicate (node_idx, child_idx); @@ -580,7 +775,7 @@ struct graph_t while (roots) { - unsigned next = HB_SET_VALUE_INVALID; + uint32_t next = HB_SET_VALUE_INVALID; if (unlikely (!check_success (!roots.in_error ()))) break; if (!roots.next (&next)) break; @@ -631,12 +826,15 @@ struct graph_t subgraph.set (root_idx, wide_parents (root_idx, parents)); find_subgraph (root_idx, subgraph); } + if (subgraph.in_error ()) + return false; unsigned original_root_idx = root_idx (); hb_map_t index_map; bool made_changes = false; for (auto entry : subgraph.iter ()) { + assert (entry.first < vertices_.length); const auto& node = vertices_[entry.first]; unsigned subgraph_incoming_edges = entry.second; @@ -648,6 +846,9 @@ struct graph_t } } + if (in_error ()) + return false; + if (!made_changes) return false; @@ -661,8 +862,8 @@ struct graph_t auto new_subgraph = + subgraph.keys () - | hb_map([&] (unsigned node_idx) { - const unsigned *v; + | hb_map([&] (uint32_t node_idx) { + const uint32_t *v; if (index_map.has (node_idx, &v)) return *v; return node_idx; }) @@ -672,10 +873,9 @@ struct graph_t remap_obj_indices (index_map, parents.iter (), true); // Update roots set with new indices as needed. - unsigned next = HB_SET_VALUE_INVALID; - while (roots.next (&next)) + for (auto next : roots) { - const unsigned *v; + const uint32_t *v; if (index_map.has (next, &v)) { roots.del (next); @@ -690,10 +890,10 @@ struct graph_t { for (const auto& link : vertices_[node_idx].obj.all_links ()) { - const unsigned *v; + hb_codepoint_t *v; if (subgraph.has (link.objidx, &v)) { - subgraph.set (link.objidx, *v + 1); + (*v)++; continue; } subgraph.set (link.objidx, 1); @@ -765,7 +965,7 @@ struct graph_t new_link->position = (const char*) new_offset - (const char*) new_v.obj.head; auto& child = vertices_[child_id]; - child.parents.push (new_parent_idx); + child.add_parent (new_parent_idx); old_v.remove_real_link (child_id, old_offset); child.remove_parent (old_parent_idx); @@ -781,7 +981,11 @@ struct graph_t if (index_map.has (node_idx)) return; - index_map.set (node_idx, duplicate (node_idx)); + unsigned clone_idx = duplicate (node_idx); + if (!check_success (clone_idx != (unsigned) -1)) + return; + + index_map.set (node_idx, clone_idx); for (const auto& l : object (node_idx).all_links ()) { duplicate_subgraph (l.objidx, index_map); } @@ -805,18 +1009,18 @@ struct graph_t clone->obj.tail = child.obj.tail; clone->distance = child.distance; clone->space = child.space; - clone->parents.reset (); + clone->reset_parents (); unsigned clone_idx = vertices_.length - 2; for (const auto& l : child.obj.real_links) { clone->obj.real_links.push (l); - vertices_[l.objidx].parents.push (clone_idx); + vertices_[l.objidx].add_parent (clone_idx); } for (const auto& l : child.obj.virtual_links) { clone->obj.virtual_links.push (l); - vertices_[l.objidx].parents.push (clone_idx); + vertices_[l.objidx].add_parent (clone_idx); } check_success (!clone->obj.real_links.in_error ()); @@ -838,6 +1042,11 @@ struct graph_t * Creates a copy of child and re-assigns the link from * parent to the clone. The copy is a shallow copy, objects * linked from child are not duplicated. + * + * Returns the index of the newly created duplicate. + * + * If the child_idx only has incoming edges from parent_idx, this + * will do nothing and return the original child_idx. */ unsigned duplicate_if_shared (unsigned parent_idx, unsigned child_idx) { @@ -851,31 +1060,33 @@ struct graph_t * Creates a copy of child and re-assigns the link from * parent to the clone. The copy is a shallow copy, objects * linked from child are not duplicated. + * + * Returns the index of the newly created duplicate. + * + * If the child_idx only has incoming edges from parent_idx, + * duplication isn't possible and this will return -1. */ unsigned duplicate (unsigned parent_idx, unsigned child_idx) { update_parents (); - unsigned links_to_child = 0; - for (const auto& l : vertices_[parent_idx].obj.all_links ()) - { - if (l.objidx == child_idx) links_to_child++; - } + const auto& child = vertices_[child_idx]; + unsigned links_to_child = child.incoming_edges_from_parent(parent_idx); - if (vertices_[child_idx].incoming_edges () <= links_to_child) + if (child.incoming_edges () <= links_to_child) { // Can't duplicate this node, doing so would orphan the original one as all remaining links // to child are from parent. - DEBUG_MSG (SUBSET_REPACK, nullptr, " Not duplicating %d => %d", + DEBUG_MSG (SUBSET_REPACK, nullptr, " Not duplicating %u => %u", parent_idx, child_idx); return -1; } - DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %d => %d", + DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %u => %u", parent_idx, child_idx); unsigned clone_idx = duplicate (child_idx); - if (clone_idx == (unsigned) -1) return false; + if (clone_idx == (unsigned) -1) return -1; // duplicate shifts the root node idx, so if parent_idx was root update it. if (parent_idx == clone_idx) parent_idx++; @@ -891,6 +1102,62 @@ struct graph_t return clone_idx; } + /* + * Creates a copy of child and re-assigns the links from + * parents to the clone. The copy is a shallow copy, objects + * linked from child are not duplicated. + * + * Returns the index of the newly created duplicate. + * + * If the child_idx only has incoming edges from parents, + * duplication isn't possible or duplication fails and this will + * return -1. + */ + unsigned duplicate (const hb_set_t* parents, unsigned child_idx) + { + if (parents->is_empty()) { + return -1; + } + + update_parents (); + + const auto& child = vertices_[child_idx]; + unsigned links_to_child = 0; + unsigned last_parent = parents->get_max(); + unsigned first_parent = parents->get_min(); + for (unsigned parent_idx : *parents) { + links_to_child += child.incoming_edges_from_parent(parent_idx); + } + + if (child.incoming_edges () <= links_to_child) + { + // Can't duplicate this node, doing so would orphan the original one as all remaining links + // to child are from parent. + DEBUG_MSG (SUBSET_REPACK, nullptr, " Not duplicating %u, ..., %u => %u", first_parent, last_parent, child_idx); + return -1; + } + + DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %u, ..., %u => %u", first_parent, last_parent, child_idx); + + unsigned clone_idx = duplicate (child_idx); + if (clone_idx == (unsigned) -1) return false; + + for (unsigned parent_idx : *parents) { + // duplicate shifts the root node idx, so if parent_idx was root update it. + if (parent_idx == clone_idx) parent_idx++; + auto& parent = vertices_[parent_idx]; + for (auto& l : parent.obj.all_links_writer ()) + { + if (l.objidx != child_idx) + continue; + + reassign_link (l, parent_idx, clone_idx); + } + } + + return clone_idx; + } + /* * Adds a new node to the graph, not connected to anything. @@ -929,7 +1196,7 @@ struct graph_t */ bool raise_childrens_priority (unsigned parent_idx) { - DEBUG_MSG (SUBSET_REPACK, nullptr, " Raising priority of all children of %d", + DEBUG_MSG (SUBSET_REPACK, nullptr, " Raising priority of all children of %u", parent_idx); // This operation doesn't change ordering until a sort is run, so no need // to invalidate positions. It does not change graph structure so no need @@ -941,6 +1208,72 @@ struct graph_t return made_change; } + bool is_fully_connected () + { + update_parents(); + + if (root().incoming_edges ()) + // Root cannot have parents. + return false; + + for (unsigned i = 0; i < root_idx (); i++) + { + if (!vertices_[i].incoming_edges ()) + return false; + } + return true; + } + +#if 0 + /* + * Saves the current graph to a packed binary format which the repacker fuzzer takes + * as a seed. + */ + void save_fuzzer_seed (hb_tag_t tag) const + { + FILE* f = fopen ("./repacker_fuzzer_seed", "w"); + fwrite ((void*) &tag, sizeof (tag), 1, f); + + uint16_t num_objects = vertices_.length; + fwrite ((void*) &num_objects, sizeof (num_objects), 1, f); + + for (const auto& v : vertices_) + { + uint16_t blob_size = v.table_size (); + fwrite ((void*) &blob_size, sizeof (blob_size), 1, f); + fwrite ((const void*) v.obj.head, blob_size, 1, f); + } + + uint16_t link_count = 0; + for (const auto& v : vertices_) + link_count += v.obj.real_links.length; + + fwrite ((void*) &link_count, sizeof (link_count), 1, f); + + typedef struct + { + uint16_t parent; + uint16_t child; + uint16_t position; + uint8_t width; + } link_t; + + for (unsigned i = 0; i < vertices_.length; i++) + { + for (const auto& l : vertices_[i].obj.real_links) + { + link_t link { + (uint16_t) i, (uint16_t) l.objidx, + (uint16_t) l.position, (uint8_t) l.width + }; + fwrite ((void*) &link, sizeof (link), 1, f); + } + } + + fclose (f); + } +#endif + void print_orphaned_nodes () { if (!DEBUG_ENABLED(SUBSET_REPACK)) return; @@ -949,10 +1282,14 @@ struct graph_t parents_invalid = true; update_parents(); + if (root().incoming_edges ()) { + DEBUG_MSG (SUBSET_REPACK, nullptr, "Root node has incoming edges."); + } + for (unsigned i = 0; i < root_idx (); i++) { const auto& v = vertices_[i]; - if (!v.parents) + if (!v.incoming_edges ()) DEBUG_MSG (SUBSET_REPACK, nullptr, "Node %u is orphaned.", i); } } @@ -984,6 +1321,8 @@ struct graph_t unsigned space_for (unsigned index, unsigned* root = nullptr) const { + loop: + assert (index < vertices_.length); const auto& node = vertices_[index]; if (node.space) { @@ -992,22 +1331,24 @@ struct graph_t return node.space; } - if (!node.parents) + if (!node.incoming_edges ()) { if (root) *root = index; return 0; } - return space_for (node.parents[0], root); + index = *node.parents_iter (); + goto loop; } void err_other_error () { this->successful = false; } size_t total_size_in_bytes () const { size_t total_size = 0; - for (unsigned i = 0; i < vertices_.length; i++) { - size_t size = vertices_[i].obj.tail - vertices_[i].obj.head; + unsigned count = vertices_.length; + for (unsigned i = 0; i < count; i++) { + size_t size = vertices_.arrayZ[i].obj.tail - vertices_.arrayZ[i].obj.head; total_size += size; } return total_size; @@ -1022,12 +1363,8 @@ struct graph_t unsigned wide_parents (unsigned node_idx, hb_set_t& parents) const { unsigned count = 0; - hb_set_t visited; - for (unsigned p : vertices_[node_idx].parents) + for (unsigned p : vertices_[node_idx].parents_iter ()) { - if (visited.has (p)) continue; - visited.add (p); - // Only real links can be wide for (const auto& l : vertices_[p].obj.real_links) { @@ -1054,17 +1391,22 @@ struct graph_t { if (!parents_invalid) return; - for (unsigned i = 0; i < vertices_.length; i++) - vertices_[i].parents.reset (); + unsigned count = vertices_.length; + + for (unsigned i = 0; i < count; i++) + vertices_.arrayZ[i].reset_parents (); - for (unsigned p = 0; p < vertices_.length; p++) + for (unsigned p = 0; p < count; p++) { - for (auto& l : vertices_[p].obj.all_links ()) - { - vertices_[l.objidx].parents.push (p); - } + for (auto& l : vertices_.arrayZ[p].obj.all_links ()) + vertices_[l.objidx].add_parent (p); } + for (unsigned i = 0; i < count; i++) + // parents arrays must be accurate or downstream operations like cycle detection + // and sorting won't work correctly. + check_success (!vertices_.arrayZ[i].in_error ()); + parents_invalid = false; } @@ -1105,15 +1447,13 @@ struct graph_t // According to https://www3.cs.stonybrook.edu/~rezaul/papers/TR-07-54.pdf // for practical performance this is faster then using a more advanced queue // (such as a fibonacci queue) with a fast decrease priority. - for (unsigned i = 0; i < vertices_.length; i++) - { - if (i == vertices_.length - 1) - vertices_[i].distance = 0; - else - vertices_[i].distance = hb_int_max (int64_t); - } + unsigned count = vertices_.length; + for (unsigned i = 0; i < count; i++) + vertices_.arrayZ[i].distance = hb_int_max (int64_t); + vertices_.tail ().distance = 0; - hb_priority_queue_t queue; + hb_priority_queue_t queue; + queue.alloc (count); queue.insert (0, vertices_.length - 1); hb_vector_t visited; @@ -1131,15 +1471,15 @@ struct graph_t { if (visited[link.objidx]) continue; - const auto& child = vertices_[link.objidx].obj; + const auto& child = vertices_.arrayZ[link.objidx].obj; unsigned link_width = link.width ? link.width : 4; // treat virtual offsets as 32 bits wide int64_t child_weight = (child.tail - child.head) + - ((int64_t) 1 << (link_width * 8)) * (vertices_[link.objidx].space + 1); + ((int64_t) 1 << (link_width * 8)) * (vertices_.arrayZ[link.objidx].space + 1); int64_t child_distance = next_distance + child_weight; - if (child_distance < vertices_[link.objidx].distance) + if (child_distance < vertices_.arrayZ[link.objidx].distance) { - vertices_[link.objidx].distance = child_distance; + vertices_.arrayZ[link.objidx].distance = child_distance; queue.insert (child_distance, link.objidx); } } @@ -1167,7 +1507,7 @@ struct graph_t unsigned old_idx = link.objidx; link.objidx = new_idx; vertices_[old_idx].remove_parent (parent_idx); - vertices_[new_idx].parents.push (parent_idx); + vertices_[new_idx].add_parent (parent_idx); } /* @@ -1183,7 +1523,7 @@ struct graph_t { for (auto& link : vertices_[i].obj.all_links_writer ()) { - const unsigned *v; + const uint32_t *v; if (!id_map.has (link.objidx, &v)) continue; if (only_wide && !(link.width == 4 && !link.is_signed)) continue; @@ -1195,17 +1535,20 @@ struct graph_t /* * Updates all objidx's in all links using the provided mapping. */ - void remap_all_obj_indices (const hb_vector_t& id_map, + bool remap_all_obj_indices (const hb_vector_t& id_map, hb_vector_t* sorted_graph) const { - for (unsigned i = 0; i < sorted_graph->length; i++) + unsigned count = sorted_graph->length; + for (unsigned i = 0; i < count; i++) { - (*sorted_graph)[i].remap_parents (id_map); - for (auto& link : (*sorted_graph)[i].obj.all_links_writer ()) + if (!(*sorted_graph)[i].remap_parents (id_map)) + return false; + for (auto& link : sorted_graph->arrayZ[i].obj.all_links_writer ()) { link.objidx = id_map[link.objidx]; } } + return true; } /* @@ -1236,7 +1579,7 @@ struct graph_t for (const auto& l : v.obj.all_links ()) find_connected_nodes (l.objidx, targets, visited, connected); - for (unsigned p : v.parents) + for (unsigned p : v.parents_iter ()) find_connected_nodes (p, targets, visited, connected); } diff --git a/libs/harfbuzz/src/graph/gsubgpos-context.cc b/libs/harfbuzz/src/graph/gsubgpos-context.cc index b2044426d..d66eb49cf 100644 --- a/libs/harfbuzz/src/graph/gsubgpos-context.cc +++ b/libs/harfbuzz/src/graph/gsubgpos-context.cc @@ -52,7 +52,11 @@ unsigned gsubgpos_graph_context_t::create_node (unsigned size) if (!buffer) return -1; - add_buffer (buffer); + if (!add_buffer (buffer)) { + // Allocation did not get stored for freeing later. + hb_free (buffer); + return -1; + } return graph.new_node (buffer, buffer + size); } diff --git a/libs/harfbuzz/src/graph/gsubgpos-context.hh b/libs/harfbuzz/src/graph/gsubgpos-context.hh index 9fe9662e6..b25d538fe 100644 --- a/libs/harfbuzz/src/graph/gsubgpos-context.hh +++ b/libs/harfbuzz/src/graph/gsubgpos-context.hh @@ -40,16 +40,16 @@ struct gsubgpos_graph_context_t graph_t& graph; unsigned lookup_list_index; hb_hashmap_t lookups; - + hb_hashmap_t subtable_to_extension; HB_INTERNAL gsubgpos_graph_context_t (hb_tag_t table_tag_, graph_t& graph_); HB_INTERNAL unsigned create_node (unsigned size); - void add_buffer (char* buffer) + bool add_buffer (char* buffer) { - graph.add_buffer (buffer); + return graph.add_buffer (buffer); } private: diff --git a/libs/harfbuzz/src/graph/gsubgpos-graph.hh b/libs/harfbuzz/src/graph/gsubgpos-graph.hh index e8d5bef9a..0f6d5662e 100644 --- a/libs/harfbuzz/src/graph/gsubgpos-graph.hh +++ b/libs/harfbuzz/src/graph/gsubgpos-graph.hh @@ -76,6 +76,7 @@ struct Lookup : public OT::Lookup { int64_t vertex_len = vertex.obj.tail - vertex.obj.head; if (vertex_len < OT::Lookup::min_size) return false; + hb_barrier (); return vertex_len >= this->get_size (); } @@ -166,7 +167,7 @@ struct Lookup : public OT::Lookup } if (all_new_subtables) { - add_sub_tables (c, this_index, type, all_new_subtables); + return add_sub_tables (c, this_index, type, all_new_subtables); } return true; @@ -184,7 +185,7 @@ struct Lookup : public OT::Lookup return sub_table->split_subtables (c, parent_idx, objidx); } - void add_sub_tables (gsubgpos_graph_context_t& c, + bool add_sub_tables (gsubgpos_graph_context_t& c, unsigned this_index, unsigned type, hb_vector_t>>& subtable_ids) @@ -200,8 +201,13 @@ struct Lookup : public OT::Lookup size_t new_size = v.table_size () + new_subtable_count * OT::Offset16::static_size; char* buffer = (char*) hb_calloc (1, new_size); - c.add_buffer (buffer); - memcpy (buffer, v.obj.head, v.table_size()); + if (!buffer) return false; + if (!c.add_buffer (buffer)) + { + hb_free (buffer); + return false; + } + hb_memcpy (buffer, v.obj.head, v.table_size()); v.obj.head = buffer; v.obj.tail = buffer + new_size; @@ -220,7 +226,7 @@ struct Lookup : public OT::Lookup if (is_ext) { unsigned ext_id = create_extension_subtable (c, subtable_id, type); - c.graph.vertices_[subtable_id].parents.push (ext_id); + c.graph.vertices_[subtable_id].add_parent (ext_id); subtable_id = ext_id; } @@ -229,7 +235,7 @@ struct Lookup : public OT::Lookup link->objidx = subtable_id; link->position = (char*) &new_lookup->subTable[offset_index++] - (char*) new_lookup; - c.graph.vertices_[subtable_id].parents.push (this_index); + c.graph.vertices_[subtable_id].add_parent (this_index); } } @@ -239,6 +245,7 @@ struct Lookup : public OT::Lookup // The head location of the lookup has changed, invalidating the lookups map entry // in the context. Update the map. c.lookups.set (this_index, new_lookup); + return true; } void fix_existing_subtable_links (gsubgpos_graph_context_t& c, @@ -293,24 +300,35 @@ struct Lookup : public OT::Lookup unsigned subtable_index) { unsigned type = lookupType; + unsigned ext_index = -1; + unsigned* existing_ext_index = nullptr; + if (c.subtable_to_extension.has(subtable_index, &existing_ext_index)) { + ext_index = *existing_ext_index; + } else { + ext_index = create_extension_subtable(c, subtable_index, type); + c.subtable_to_extension.set(subtable_index, ext_index); + } - unsigned ext_index = create_extension_subtable(c, subtable_index, type); if (ext_index == (unsigned) -1) return false; + auto& subtable_vertex = c.graph.vertices_[subtable_index]; auto& lookup_vertex = c.graph.vertices_[lookup_index]; for (auto& l : lookup_vertex.obj.real_links.writer ()) { - if (l.objidx == subtable_index) + if (l.objidx == subtable_index) { // Change lookup to point at the extension. l.objidx = ext_index; + if (existing_ext_index) + subtable_vertex.remove_parent(lookup_index); + } } // Make extension point at the subtable. auto& ext_vertex = c.graph.vertices_[ext_index]; - auto& subtable_vertex = c.graph.vertices_[subtable_index]; - ext_vertex.parents.push (lookup_index); - subtable_vertex.remap_parent (lookup_index, ext_index); + ext_vertex.add_parent (lookup_index); + if (!existing_ext_index) + subtable_vertex.remap_parent (lookup_index, ext_index); return true; } @@ -334,6 +352,7 @@ struct LookupList : public OT::LookupList { int64_t vertex_len = vertex.obj.tail - vertex.obj.head; if (vertex_len < OT::LookupList::min_size) return false; + hb_barrier (); return vertex_len >= OT::LookupList::item_size * this->len; } }; @@ -347,6 +366,7 @@ struct GSTAR : public OT::GSUBGPOS GSTAR* gstar = (GSTAR*) r.obj.head; if (!gstar || !gstar->sanitize (r)) return nullptr; + hb_barrier (); return gstar; } @@ -355,7 +375,7 @@ struct GSTAR : public OT::GSUBGPOS { switch (u.version.major) { case 1: return u.version1.get_lookup_list_offset (); -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K case 2: return u.version2.get_lookup_list_offset (); #endif default: return 0; @@ -366,6 +386,7 @@ struct GSTAR : public OT::GSUBGPOS { int64_t len = vertex.obj.tail - vertex.obj.head; if (len < OT::GSUBGPOS::min_size) return false; + hb_barrier (); return len >= get_size (); } @@ -374,7 +395,7 @@ struct GSTAR : public OT::GSUBGPOS { switch (u.version.major) { case 1: find_lookups (graph, lookups); break; -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K case 2: find_lookups (graph, lookups); break; #endif } diff --git a/libs/harfbuzz/src/graph/markbasepos-graph.hh b/libs/harfbuzz/src/graph/markbasepos-graph.hh index e42a6042c..fb4166128 100644 --- a/libs/harfbuzz/src/graph/markbasepos-graph.hh +++ b/libs/harfbuzz/src/graph/markbasepos-graph.hh @@ -40,6 +40,7 @@ struct AnchorMatrix : public OT::Layout::GPOS_impl::AnchorMatrix { int64_t vertex_len = vertex.obj.tail - vertex.obj.head; if (vertex_len < AnchorMatrix::min_size) return false; + hb_barrier (); return vertex_len >= AnchorMatrix::min_size + OT::Offset16::static_size * class_count * this->rows; @@ -112,7 +113,7 @@ struct AnchorMatrix : public OT::Layout::GPOS_impl::AnchorMatrix auto& child = c.graph.vertices_[child_idx]; child.remove_parent (this_index); - o.real_links.remove (i); + o.real_links.remove_unordered (i); num_links--; i--; } @@ -128,6 +129,7 @@ struct MarkArray : public OT::Layout::GPOS_impl::MarkArray int64_t vertex_len = vertex.obj.tail - vertex.obj.head; unsigned min_size = MarkArray::min_size; if (vertex_len < min_size) return false; + hb_barrier (); return vertex_len >= get_size (); } @@ -217,7 +219,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2::min_size + + OT::Layout::GPOS_impl::MarkBasePosFormat1_2::min_size + MarkArray::min_size + AnchorMatrix::min_size + c.graph.vertices_[base_coverage_id].table_size (); @@ -318,8 +320,11 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2 class_to_info; - unsigned class_count= classCount; - class_to_info.resize (class_count); + unsigned class_count = classCount; + if (!class_count) return class_to_info; + + if (!class_to_info.resize (class_count)) + return hb_vector_t(); auto mark_array = c.graph.as_table (this_index, &markArray); if (!mark_array) return hb_vector_t (); @@ -327,6 +332,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2= class_count) continue; class_to_info[klass].marks.add (mark); } @@ -335,6 +341,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2= class_count) continue; class_to_info[klass].child_indices.push (link.objidx); } @@ -372,7 +379,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2iter ()) + + hb_enumerate (mark_coverage.table->iter ()) | hb_filter (marks, hb_first) | hb_map_retains_sorting (hb_second) ; @@ -431,7 +438,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2iter ()) + + hb_enumerate (mark_coverage.table->iter ()) | hb_filter (marks, hb_first) | hb_map_retains_sorting (hb_second) ; @@ -477,9 +484,9 @@ struct MarkBasePos : public OT::Layout::GPOS_impl::MarkBasePos switch (u.format) { case 1: return ((MarkBasePosFormat1*)(&u.format1))->split_subtables (c, parent_index, this_index); -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K case 2: HB_FALLTHROUGH; - // Don't split 24bit PairPos's. + // Don't split 24bit MarkBasePos's. #endif default: return hb_vector_t (); @@ -490,11 +497,12 @@ struct MarkBasePos : public OT::Layout::GPOS_impl::MarkBasePos { int64_t vertex_len = vertex.obj.tail - vertex.obj.head; if (vertex_len < u.format.get_size ()) return false; + hb_barrier (); switch (u.format) { case 1: return ((MarkBasePosFormat1*)(&u.format1))->sanitize (vertex); -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K case 2: HB_FALLTHROUGH; #endif default: diff --git a/libs/harfbuzz/src/graph/pairpos-graph.hh b/libs/harfbuzz/src/graph/pairpos-graph.hh index 8040778ea..fd46861de 100644 --- a/libs/harfbuzz/src/graph/pairpos-graph.hh +++ b/libs/harfbuzz/src/graph/pairpos-graph.hh @@ -42,6 +42,7 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3::min_size; if (vertex_len < min_size) return false; + hb_barrier (); return vertex_len >= min_size + pairSet.get_size () - pairSet.len.get_size(); @@ -198,6 +199,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4::min_size; if (vertex_len < min_size) return false; + hb_barrier (); const unsigned class1_count = class1Count; return vertex_len >= @@ -215,7 +217,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4iter () | hb_map_retains_sorting ([&] (hb_codepoint_t gid) { - return hb_pair_t (gid, class_def_1->get_class (gid)); + return hb_codepoint_pair_t (gid, class_def_1->get_class (gid)); }) ; class_def_size_estimator_t estimator (gid_and_class); @@ -245,8 +247,8 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4iter () | hb_map_retains_sorting ([&] (hb_codepoint_t gid) { - return hb_pair_t (gid, class_def_1_table->get_class (gid)); + return hb_codepoint_pair_t (gid, class_def_1_table->get_class (gid)); }) | hb_filter ([&] (hb_codepoint_t klass) { return klass >= start && klass < end; }, hb_second) - | hb_map_retains_sorting ([&] (hb_pair_t gid_and_class) { + | hb_map_retains_sorting ([&] (hb_codepoint_pair_t gid_and_class) { // Classes must be from 0...N so subtract start - return hb_pair_t (gid_and_class.first, gid_and_class.second - start); + return hb_codepoint_pair_t (gid_and_class.first, gid_and_class.second - start); }) ; @@ -419,7 +423,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4width = SmallTypes::size; class_def_link->objidx = class_def_2_id; class_def_link->position = 10; - graph.vertices_[class_def_2_id].parents.push (pair_pos_prime_id); + graph.vertices_[class_def_2_id].add_parent (pair_pos_prime_id); graph.duplicate (pair_pos_prime_id, class_def_2_id); return pair_pos_prime_id; @@ -434,7 +438,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4values[0], + hb_memcpy (&pair_pos_prime->values[0], start_addr, num_records * split_context.class1_record_size); @@ -519,7 +523,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4iter () | hb_map_retains_sorting ([&] (hb_codepoint_t gid) { - return hb_pair_t (gid, class_def_1.table->get_class (gid)); + return hb_codepoint_pair_t (gid, class_def_1.table->get_class (gid)); }) | hb_filter ([&] (hb_codepoint_t klass) { return klass < count; @@ -611,7 +615,7 @@ struct PairPos : public OT::Layout::GPOS_impl::PairPos return ((PairPosFormat1*)(&u.format1))->split_subtables (c, parent_index, this_index); case 2: return ((PairPosFormat2*)(&u.format2))->split_subtables (c, parent_index, this_index); -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K case 3: HB_FALLTHROUGH; case 4: HB_FALLTHROUGH; // Don't split 24bit PairPos's. @@ -625,13 +629,14 @@ struct PairPos : public OT::Layout::GPOS_impl::PairPos { int64_t vertex_len = vertex.obj.tail - vertex.obj.head; if (vertex_len < u.format.get_size ()) return false; + hb_barrier (); switch (u.format) { case 1: return ((PairPosFormat1*)(&u.format1))->sanitize (vertex); case 2: return ((PairPosFormat2*)(&u.format2))->sanitize (vertex); -#ifndef HB_NO_BORING_EXPANSION +#ifndef HB_NO_BEYOND_64K case 3: HB_FALLTHROUGH; case 4: HB_FALLTHROUGH; #endif diff --git a/libs/harfbuzz/src/graph/serialize.hh b/libs/harfbuzz/src/graph/serialize.hh index ecc6cc5ae..06e4bf44d 100644 --- a/libs/harfbuzz/src/graph/serialize.hh +++ b/libs/harfbuzz/src/graph/serialize.hh @@ -33,6 +33,23 @@ struct overflow_record_t { unsigned parent; unsigned child; + + bool operator != (const overflow_record_t o) const + { return !(*this == o); } + + inline bool operator == (const overflow_record_t& o) const + { + return parent == o.parent && + child == o.child; + } + + inline uint32_t hash () const + { + uint32_t current = 0; + current = current * 31 + hb_hash (parent); + current = current * 31 + hb_hash (child); + return current; + } }; inline @@ -94,14 +111,15 @@ will_overflow (graph_t& graph, if (overflows) overflows->resize (0); graph.update_positions (); + hb_hashmap_t record_set; const auto& vertices = graph.vertices_; for (int parent_idx = vertices.length - 1; parent_idx >= 0; parent_idx--) { // Don't need to check virtual links for overflow - for (const auto& link : vertices[parent_idx].obj.real_links) + for (const auto& link : vertices.arrayZ[parent_idx].obj.real_links) { int64_t offset = compute_offset (graph, parent_idx, link); - if (is_valid_offset (offset, link)) + if (likely (is_valid_offset (offset, link))) continue; if (!overflows) return true; @@ -109,7 +127,10 @@ will_overflow (graph_t& graph, overflow_record_t r; r.parent = parent_idx; r.child = link.objidx; + if (record_set.has(&r)) continue; // don't keep duplicate overflows. + overflows->push (r); + record_set.set(&r, true); } } @@ -132,8 +153,8 @@ void print_overflows (graph_t& graph, const auto& child = graph.vertices_[o.child]; DEBUG_MSG (SUBSET_REPACK, nullptr, " overflow from " - "%4d (%4d in, %4d out, space %2d) => " - "%4d (%4d in, %4d out, space %2d)", + "%4u (%4u in, %4u out, space %2u) => " + "%4u (%4u in, %4u out, space %2u)", o.parent, parent.incoming_edges (), parent.obj.real_links.length + parent.obj.virtual_links.length, @@ -144,7 +165,7 @@ void print_overflows (graph_t& graph, graph.space_for (o.child)); } if (overflows.length > 10) { - DEBUG_MSG (SUBSET_REPACK, nullptr, " ... plus %d more overflows.", overflows.length - 10); + DEBUG_MSG (SUBSET_REPACK, nullptr, " ... plus %u more overflows.", overflows.length - 10); } } @@ -205,6 +226,9 @@ inline hb_blob_t* serialize (const graph_t& graph) { hb_vector_t buffer; size_t size = graph.total_size_in_bytes (); + + if (!size) return hb_blob_get_empty (); + if (!buffer.alloc (size)) { DEBUG_MSG (SUBSET_REPACK, nullptr, "Unable to allocate output buffer."); return nullptr; @@ -223,7 +247,7 @@ inline hb_blob_t* serialize (const graph_t& graph) return nullptr; } - memcpy (start, vertices[i].obj.head, size); + hb_memcpy (start, vertices[i].obj.head, size); // Only real links needs to be serialized. for (const auto& link : vertices[i].obj.real_links) diff --git a/libs/harfbuzz/src/graph/test-classdef-graph.cc b/libs/harfbuzz/src/graph/test-classdef-graph.cc index 55854ff5c..2da934811 100644 --- a/libs/harfbuzz/src/graph/test-classdef-graph.cc +++ b/libs/harfbuzz/src/graph/test-classdef-graph.cc @@ -26,27 +26,119 @@ #include "gsubgpos-context.hh" #include "classdef-graph.hh" +#include "hb-iter.hh" +#include "hb-serialize.hh" -typedef hb_pair_t gid_and_class_t; +typedef hb_codepoint_pair_t gid_and_class_t; typedef hb_vector_t gid_and_class_list_t; +template +static unsigned actual_class_def_size(It glyph_and_class) { + char buffer[100]; + hb_serialize_context_t serializer(buffer, 100); + OT::ClassDef_serialize (&serializer, glyph_and_class); + serializer.end_serialize (); + assert(!serializer.in_error()); -static bool incremental_size_is (const gid_and_class_list_t& list, unsigned klass, - unsigned cov_expected, unsigned class_def_expected) + hb_blob_t* blob = serializer.copy_blob(); + unsigned size = hb_blob_get_length(blob); + hb_blob_destroy(blob); + return size; +} + +static unsigned actual_class_def_size(gid_and_class_list_t consecutive_map, hb_vector_t classes) { + auto filtered_it = + + consecutive_map.as_sorted_array().iter() + | hb_filter([&] (unsigned c) { + for (unsigned klass : classes) { + if (c == klass) { + return true; + } + } + return false; + }, hb_second); + return actual_class_def_size(+ filtered_it); +} + +template +static unsigned actual_coverage_size(It glyphs) { + char buffer[100]; + hb_serialize_context_t serializer(buffer, 100); + OT::Layout::Common::Coverage_serialize (&serializer, glyphs); + serializer.end_serialize (); + assert(!serializer.in_error()); + + hb_blob_t* blob = serializer.copy_blob(); + unsigned size = hb_blob_get_length(blob); + hb_blob_destroy(blob); + return size; +} + +static unsigned actual_coverage_size(gid_and_class_list_t consecutive_map, hb_vector_t classes) { + auto filtered_it = + + consecutive_map.as_sorted_array().iter() + | hb_filter([&] (unsigned c) { + for (unsigned klass : classes) { + if (c == klass) { + return true; + } + } + return false; + }, hb_second); + return actual_coverage_size(+ filtered_it | hb_map_retains_sorting(hb_first)); +} + +static bool check_coverage_size(graph::class_def_size_estimator_t& estimator, + const gid_and_class_list_t& map, + hb_vector_t klasses) +{ + unsigned result = estimator.coverage_size(); + unsigned expected = actual_coverage_size(map, klasses); + if (result != expected) { + printf ("FAIL: estimated coverage expected size %u but was %u\n", expected, result); + return false; + } + return true; +} + +static bool check_add_class_def_size(graph::class_def_size_estimator_t& estimator, + const gid_and_class_list_t& map, + unsigned klass, hb_vector_t klasses) +{ + unsigned result = estimator.add_class_def_size(klass); + unsigned expected = actual_class_def_size(map, klasses); + if (result != expected) { + printf ("FAIL: estimated class def expected size %u but was %u\n", expected, result); + return false; + } + + return check_coverage_size(estimator, map, klasses); +} + +static bool check_add_class_def_size (const gid_and_class_list_t& list, unsigned klass) { graph::class_def_size_estimator_t estimator (list.iter ()); - unsigned result = estimator.incremental_coverage_size (klass); - if (result != cov_expected) + unsigned result = estimator.add_class_def_size (klass); + auto filtered_it = + + list.as_sorted_array().iter() + | hb_filter([&] (unsigned c) { + return c == klass; + }, hb_second); + + unsigned expected = actual_class_def_size(filtered_it); + if (result != expected) { - printf ("FAIL: coverage expected size %u but was %u\n", cov_expected, result); + printf ("FAIL: class def expected size %u but was %u\n", expected, result); return false; } - result = estimator.incremental_class_def_size (klass); - if (result != class_def_expected) + auto cov_it = + filtered_it | hb_map_retains_sorting(hb_first); + result = estimator.coverage_size (); + expected = actual_coverage_size(cov_it); + if (result != expected) { - printf ("FAIL: class def expected size %u but was %u\n", class_def_expected, result); + printf ("FAIL: coverage expected size %u but was %u\n", expected, result); return false; } @@ -57,43 +149,45 @@ static void test_class_and_coverage_size_estimates () { gid_and_class_list_t empty = { }; - assert (incremental_size_is (empty, 0, 0, 0)); - assert (incremental_size_is (empty, 1, 0, 0)); + assert (check_add_class_def_size (empty, 0)); + assert (check_add_class_def_size (empty, 1)); gid_and_class_list_t class_zero = { {5, 0}, }; - assert (incremental_size_is (class_zero, 0, 2, 0)); + assert (check_add_class_def_size (class_zero, 0)); gid_and_class_list_t consecutive = { {4, 0}, {5, 0}, + {6, 1}, {7, 1}, + {8, 2}, {9, 2}, {10, 2}, {11, 2}, }; - assert (incremental_size_is (consecutive, 0, 4, 0)); - assert (incremental_size_is (consecutive, 1, 4, 4)); - assert (incremental_size_is (consecutive, 2, 8, 6)); + assert (check_add_class_def_size (consecutive, 0)); + assert (check_add_class_def_size (consecutive, 1)); + assert (check_add_class_def_size (consecutive, 2)); gid_and_class_list_t non_consecutive = { {4, 0}, - {5, 0}, + {6, 0}, - {6, 1}, - {7, 1}, + {8, 1}, + {10, 1}, {9, 2}, {10, 2}, {11, 2}, - {12, 2}, + {13, 2}, }; - assert (incremental_size_is (non_consecutive, 0, 4, 0)); - assert (incremental_size_is (non_consecutive, 1, 4, 6)); - assert (incremental_size_is (non_consecutive, 2, 8, 6)); + assert (check_add_class_def_size (non_consecutive, 0)); + assert (check_add_class_def_size (non_consecutive, 1)); + assert (check_add_class_def_size (non_consecutive, 2)); gid_and_class_list_t multiple_ranges = { {4, 0}, @@ -108,12 +202,95 @@ static void test_class_and_coverage_size_estimates () {12, 1}, {13, 1}, }; - assert (incremental_size_is (multiple_ranges, 0, 4, 0)); - assert (incremental_size_is (multiple_ranges, 1, 2 * 6, 3 * 6)); + assert (check_add_class_def_size (multiple_ranges, 0)); + assert (check_add_class_def_size (multiple_ranges, 1)); +} + +static void test_running_class_and_coverage_size_estimates () { + // #### With consecutive gids: switches formats ### + gid_and_class_list_t consecutive_map = { + // range 1-4 (f1: 8 bytes), (f2: 6 bytes) + {1, 1}, + {2, 1}, + {3, 1}, + {4, 1}, + + // (f1: 2 bytes), (f2: 6 bytes) + {5, 2}, + + // (f1: 14 bytes), (f2: 6 bytes) + {6, 3}, + {7, 3}, + {8, 3}, + {9, 3}, + {10, 3}, + {11, 3}, + {12, 3}, + }; + + graph::class_def_size_estimator_t estimator1(consecutive_map.iter()); + assert(check_add_class_def_size(estimator1, consecutive_map, 1, {1})); + assert(check_add_class_def_size(estimator1, consecutive_map, 2, {1, 2})); + assert(check_add_class_def_size(estimator1, consecutive_map, 2, {1, 2})); // check that adding the same class again works + assert(check_add_class_def_size(estimator1, consecutive_map, 3, {1, 2, 3})); + + estimator1.reset(); + assert(check_add_class_def_size(estimator1, consecutive_map, 2, {2})); + assert(check_add_class_def_size(estimator1, consecutive_map, 3, {2, 3})); + + // #### With non-consecutive gids: always uses format 2 ### + gid_and_class_list_t non_consecutive_map = { + // range 1-4 (f1: 8 bytes), (f2: 6 bytes) + {1, 1}, + {2, 1}, + {3, 1}, + {4, 1}, + + // (f1: 2 bytes), (f2: 12 bytes) + {6, 2}, + {8, 2}, + + // (f1: 14 bytes), (f2: 6 bytes) + {9, 3}, + {10, 3}, + {11, 3}, + {12, 3}, + {13, 3}, + {14, 3}, + {15, 3}, + }; + + graph::class_def_size_estimator_t estimator2(non_consecutive_map.iter()); + assert(check_add_class_def_size(estimator2, non_consecutive_map, 1, {1})); + assert(check_add_class_def_size(estimator2, non_consecutive_map, 2, {1, 2})); + assert(check_add_class_def_size(estimator2, non_consecutive_map, 3, {1, 2, 3})); + + estimator2.reset(); + assert(check_add_class_def_size(estimator2, non_consecutive_map, 2, {2})); + assert(check_add_class_def_size(estimator2, non_consecutive_map, 3, {2, 3})); +} + +static void test_running_class_size_estimates_with_locally_consecutive_glyphs () { + gid_and_class_list_t map = { + {1, 1}, + {6, 2}, + {7, 3}, + }; + + graph::class_def_size_estimator_t estimator(map.iter()); + assert(check_add_class_def_size(estimator, map, 1, {1})); + assert(check_add_class_def_size(estimator, map, 2, {1, 2})); + assert(check_add_class_def_size(estimator, map, 3, {1, 2, 3})); + + estimator.reset(); + assert(check_add_class_def_size(estimator, map, 2, {2})); + assert(check_add_class_def_size(estimator, map, 3, {2, 3})); } int main (int argc, char **argv) { test_class_and_coverage_size_estimates (); + test_running_class_and_coverage_size_estimates (); + test_running_class_size_estimates_with_locally_consecutive_glyphs (); } diff --git a/libs/harfbuzz/src/harfbuzz-cairo.pc.in b/libs/harfbuzz/src/harfbuzz-cairo.pc.in new file mode 100644 index 000000000..06ba8047c --- /dev/null +++ b/libs/harfbuzz/src/harfbuzz-cairo.pc.in @@ -0,0 +1,13 @@ +prefix=%prefix% +exec_prefix=%exec_prefix% +libdir=%libdir% +includedir=%includedir% + +Name: harfbuzz cairo integration +Description: HarfBuzz cairo integration +Version: %VERSION% + +Requires: harfbuzz = %VERSION% +Requires.private: cairo +Libs: -L${libdir} -lharfbuzz-cairo +Cflags: -I${includedir}/harfbuzz diff --git a/libs/harfbuzz/src/harfbuzz-config.cmake.in b/libs/harfbuzz/src/harfbuzz-config.cmake.in index 304410d9b..6abe2d62d 100644 --- a/libs/harfbuzz/src/harfbuzz-config.cmake.in +++ b/libs/harfbuzz/src/harfbuzz-config.cmake.in @@ -1,86 +1,32 @@ -# Set these variables so that the `${prefix}/lib` expands to something we can -# remove. -set(_harfbuzz_remove_string "REMOVE_ME") -set(exec_prefix "${_harfbuzz_remove_string}") -set(prefix "${_harfbuzz_remove_string}") +@PACKAGE_INIT@ -# Compute the installation prefix by stripping components from our current -# location. -get_filename_component(_harfbuzz_prefix "${CMAKE_CURRENT_LIST_DIR}" DIRECTORY) -get_filename_component(_harfbuzz_prefix "${_harfbuzz_prefix}" DIRECTORY) -set(_harfbuzz_libdir "@libdir@") -string(REPLACE "${_harfbuzz_remove_string}/" "" _harfbuzz_libdir "${_harfbuzz_libdir}") -set(_harfbuzz_libdir_iter "${_harfbuzz_libdir}") -while (_harfbuzz_libdir_iter) - set(_harfbuzz_libdir_prev_iter "${_harfbuzz_libdir_iter}") - get_filename_component(_harfbuzz_libdir_iter "${_harfbuzz_libdir_iter}" DIRECTORY) - if (_harfbuzz_libdir_prev_iter STREQUAL _harfbuzz_libdir_iter) - break() - endif () - get_filename_component(_harfbuzz_prefix "${_harfbuzz_prefix}" DIRECTORY) -endwhile () -unset(_harfbuzz_libdir_iter) - -# Get the include subdir. -set(_harfbuzz_includedir "@includedir@") -string(REPLACE "${_harfbuzz_remove_string}/" "" _harfbuzz_includedir "${_harfbuzz_includedir}") - -# Extract version information from libtool. -set(_harfbuzz_version_info "@HB_LIBTOOL_VERSION_INFO@") -string(REPLACE ":" ";" _harfbuzz_version_info "${_harfbuzz_version_info}") -list(GET _harfbuzz_version_info 0 - _harfbuzz_current) -list(GET _harfbuzz_version_info 1 - _harfbuzz_revision) -list(GET _harfbuzz_version_info 2 - _harfbuzz_age) -unset(_harfbuzz_version_info) - -if (APPLE) - set(_harfbuzz_lib_suffix ".0${CMAKE_SHARED_LIBRARY_SUFFIX}") -elseif (UNIX) - set(_harfbuzz_lib_suffix "${CMAKE_SHARED_LIBRARY_SUFFIX}.0.${_harfbuzz_current}.${_harfbuzz_revision}") -else () - # Unsupported. - set(harfbuzz_FOUND 0) -endif () +set_and_check(HARFBUZZ_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@") # Add the libraries. -add_library(harfbuzz::harfbuzz SHARED IMPORTED) +add_library(harfbuzz::harfbuzz @HB_LIBRARY_TYPE@ IMPORTED) set_target_properties(harfbuzz::harfbuzz PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_prefix}/${_harfbuzz_includedir}/harfbuzz" - IMPORTED_LOCATION "${_harfbuzz_prefix}/${_harfbuzz_libdir}/libharfbuzz${_harfbuzz_lib_suffix}") + INTERFACE_INCLUDE_DIRECTORIES "@PACKAGE_INCLUDE_INSTALL_DIR@" + IMPORTED_LOCATION "@PACKAGE_CMAKE_INSTALL_LIBDIR@/@HB_LIB_PREFIX@harfbuzz@HB_LIB_SUFFIX@") -add_library(harfbuzz::icu SHARED IMPORTED) +add_library(harfbuzz::icu @HB_LIBRARY_TYPE@ IMPORTED) set_target_properties(harfbuzz::icu PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_prefix}/${_harfbuzz_includedir}/harfbuzz" + INTERFACE_INCLUDE_DIRECTORIES "@PACKAGE_INCLUDE_INSTALL_DIR@" INTERFACE_LINK_LIBRARIES "harfbuzz::harfbuzz" - IMPORTED_LOCATION "${_harfbuzz_prefix}/${_harfbuzz_libdir}/libharfbuzz-icu${_harfbuzz_lib_suffix}") + IMPORTED_LOCATION "@PACKAGE_CMAKE_INSTALL_LIBDIR@/@HB_LIB_PREFIX@harfbuzz-icu@HB_LIB_SUFFIX@") -add_library(harfbuzz::subset SHARED IMPORTED) +add_library(harfbuzz::subset @HB_LIBRARY_TYPE@ IMPORTED) set_target_properties(harfbuzz::subset PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_prefix}/${_harfbuzz_includedir}/harfbuzz" + INTERFACE_INCLUDE_DIRECTORIES "@PACKAGE_INCLUDE_INSTALL_DIR@" INTERFACE_LINK_LIBRARIES "harfbuzz::harfbuzz" - IMPORTED_LOCATION "${_harfbuzz_prefix}/${_harfbuzz_libdir}/libharfbuzz-subset${_harfbuzz_lib_suffix}") + IMPORTED_LOCATION "@PACKAGE_CMAKE_INSTALL_LIBDIR@/@HB_LIB_PREFIX@harfbuzz-subset@HB_LIB_SUFFIX@") # Only add the gobject library if it was built. -set(_harfbuzz_have_gobject "@have_gobject@") -if (_harfbuzz_have_gobject) - add_library(harfbuzz::gobject SHARED IMPORTED) +if (@HB_HAVE_GOBJECT@) + add_library(harfbuzz::gobject @HB_LIBRARY_TYPE@ IMPORTED) set_target_properties(harfbuzz::gobject PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_prefix}/${_harfbuzz_includedir}/harfbuzz" + INTERFACE_INCLUDE_DIRECTORIES "@PACKAGE_INCLUDE_INSTALL_DIR@" INTERFACE_LINK_LIBRARIES "harfbuzz::harfbuzz" - IMPORTED_LOCATION "${_harfbuzz_prefix}/${_harfbuzz_libdir}/libharfbuzz-gobject${_harfbuzz_lib_suffix}") + IMPORTED_LOCATION "@PACKAGE_CMAKE_INSTALL_LIBDIR@/@HB_LIB_PREFIX@harfbuzz-gobject@HB_LIB_SUFFIX@") endif () -# Clean out variables we used in our scope. -unset(_harfbuzz_lib_suffix) -unset(_harfbuzz_current) -unset(_harfbuzz_revision) -unset(_harfbuzz_age) -unset(_harfbuzz_includedir) -unset(_harfbuzz_libdir) -unset(_harfbuzz_prefix) -unset(exec_prefix) -unset(prefix) -unset(_harfbuzz_remove_string) +check_required_components(harfbuzz) diff --git a/libs/harfbuzz/src/harfbuzz-subset.cc b/libs/harfbuzz/src/harfbuzz-subset.cc index a43485e6f..05483b14c 100644 --- a/libs/harfbuzz/src/harfbuzz-subset.cc +++ b/libs/harfbuzz/src/harfbuzz-subset.cc @@ -1,3 +1,4 @@ +#include "OT/Var/VARC/VARC.cc" #include "graph/gsubgpos-context.cc" #include "hb-aat-layout.cc" #include "hb-aat-map.cc" @@ -7,6 +8,7 @@ #include "hb-buffer.cc" #include "hb-common.cc" #include "hb-draw.cc" +#include "hb-face-builder.cc" #include "hb-face.cc" #include "hb-fallback-shape.cc" #include "hb-font.cc" @@ -40,6 +42,9 @@ #include "hb-ot-shaper-vowel-constraints.cc" #include "hb-ot-tag.cc" #include "hb-ot-var.cc" +#include "hb-outline.cc" +#include "hb-paint-extents.cc" +#include "hb-paint.cc" #include "hb-set.cc" #include "hb-shape-plan.cc" #include "hb-shape.cc" @@ -50,6 +55,8 @@ #include "hb-subset-cff1.cc" #include "hb-subset-cff2.cc" #include "hb-subset-input.cc" +#include "hb-subset-instancer-iup.cc" +#include "hb-subset-instancer-solver.cc" #include "hb-subset-plan.cc" #include "hb-subset-repacker.cc" #include "hb-subset.cc" diff --git a/libs/harfbuzz/src/harfbuzz.cc b/libs/harfbuzz/src/harfbuzz.cc index fe4e21db0..9ff800daa 100644 --- a/libs/harfbuzz/src/harfbuzz.cc +++ b/libs/harfbuzz/src/harfbuzz.cc @@ -1,3 +1,4 @@ +#include "OT/Var/VARC/VARC.cc" #include "hb-aat-layout.cc" #include "hb-aat-map.cc" #include "hb-blob.cc" @@ -5,9 +6,11 @@ #include "hb-buffer-verify.cc" #include "hb-buffer.cc" #include "hb-common.cc" -#include "hb-coretext.cc" +#include "hb-coretext-font.cc" +#include "hb-coretext-shape.cc" #include "hb-directwrite.cc" #include "hb-draw.cc" +#include "hb-face-builder.cc" #include "hb-face.cc" #include "hb-fallback-shape.cc" #include "hb-font.cc" @@ -45,6 +48,9 @@ #include "hb-ot-shaper-vowel-constraints.cc" #include "hb-ot-tag.cc" #include "hb-ot-var.cc" +#include "hb-outline.cc" +#include "hb-paint-extents.cc" +#include "hb-paint.cc" #include "hb-set.cc" #include "hb-shape-plan.cc" #include "hb-shape.cc" @@ -54,3 +60,5 @@ #include "hb-ucd.cc" #include "hb-unicode.cc" #include "hb-uniscribe.cc" +#include "hb-wasm-api.cc" +#include "hb-wasm-shape.cc" diff --git a/libs/harfbuzz/src/hb-aat-layout-ankr-table.hh b/libs/harfbuzz/src/hb-aat-layout-ankr-table.hh index 63fac8452..dbb38b1bc 100644 --- a/libs/harfbuzz/src/hb-aat-layout-ankr-table.hh +++ b/libs/harfbuzz/src/hb-aat-layout-ankr-table.hh @@ -75,6 +75,7 @@ struct ankr { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && + hb_barrier () && version == 0 && c->check_range (this, anchorData) && lookupTable.sanitize (c, this, &(this+anchorData)))); diff --git a/libs/harfbuzz/src/hb-aat-layout-bsln-table.hh b/libs/harfbuzz/src/hb-aat-layout-bsln-table.hh index bf12d2e69..8e42fab2e 100644 --- a/libs/harfbuzz/src/hb-aat-layout-bsln-table.hh +++ b/libs/harfbuzz/src/hb-aat-layout-bsln-table.hh @@ -123,6 +123,7 @@ struct bsln TRACE_SANITIZE (this); if (unlikely (!(c->check_struct (this) && defaultBaseline < 32))) return_trace (false); + hb_barrier (); switch (format) { diff --git a/libs/harfbuzz/src/hb-aat-layout-common.hh b/libs/harfbuzz/src/hb-aat-layout-common.hh index 6cbed8269..2ea86a2a1 100644 --- a/libs/harfbuzz/src/hb-aat-layout-common.hh +++ b/libs/harfbuzz/src/hb-aat-layout-common.hh @@ -28,6 +28,7 @@ #define HB_AAT_LAYOUT_COMMON_HH #include "hb-aat-layout.hh" +#include "hb-aat-map.hh" #include "hb-open-type.hh" namespace OT { @@ -38,11 +39,56 @@ namespace AAT { using namespace OT; +#define HB_AAT_BUFFER_DIGEST_THRESHOLD 32 + +struct ankr; + +struct hb_aat_apply_context_t : + hb_dispatch_context_t +{ + const char *get_name () { return "APPLY"; } + template + return_t dispatch (const T &obj, Ts&&... ds) + { return obj.apply (this, std::forward (ds)...); } + static return_t default_return_value () { return false; } + bool stop_sublookup_iteration (return_t r) const { return r; } + + const hb_ot_shape_plan_t *plan; + hb_font_t *font; + hb_face_t *face; + hb_buffer_t *buffer; + hb_sanitize_context_t sanitizer; + const ankr *ankr_table; + const OT::GDEF *gdef_table; + const hb_sorted_vector_t *range_flags = nullptr; + hb_set_digest_t buffer_digest = hb_set_digest_t::full (); + hb_set_digest_t machine_glyph_set = hb_set_digest_t::full (); + hb_set_digest_t left_set = hb_set_digest_t::full (); + hb_set_digest_t right_set = hb_set_digest_t::full (); + hb_mask_t subtable_flags = 0; + + /* Unused. For debug tracing only. */ + unsigned int lookup_index; + + HB_INTERNAL hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_, + hb_font_t *font_, + hb_buffer_t *buffer_, + hb_blob_t *blob = const_cast (&Null (hb_blob_t))); + + HB_INTERNAL ~hb_aat_apply_context_t (); + + HB_INTERNAL void set_ankr_table (const AAT::ankr *ankr_table_); + + void set_lookup_index (unsigned int i) { lookup_index = i; } +}; + /* * Lookup Table */ +enum { DELETED_GLYPH = 0xFFFF }; + template struct Lookup; template @@ -57,6 +103,12 @@ struct LookupFormat0 return &arrayZ[glyph_id]; } + template + void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const + { + glyphs.add_range (0, num_glyphs - 1); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -85,6 +137,14 @@ struct LookupSegmentSingle int cmp (hb_codepoint_t g) const { return g < first ? -1 : g <= last ? 0 : +1 ; } + template + void collect_glyphs (set_t &glyphs) const + { + if (first == DELETED_GLYPH) + return; + glyphs.add_range (first, last); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -115,6 +175,14 @@ struct LookupFormat2 return v ? &v->value : nullptr; } + template + void collect_glyphs (set_t &glyphs) const + { + unsigned count = segments.get_length (); + for (unsigned int i = 0; i < count; i++) + segments[i].collect_glyphs (glyphs); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -146,6 +214,14 @@ struct LookupSegmentArray return first <= glyph_id && glyph_id <= last ? &(base+valuesZ)[glyph_id - first] : nullptr; } + template + void collect_glyphs (set_t &glyphs) const + { + if (first == DELETED_GLYPH) + return; + glyphs.add_range (first, last); + } + int cmp (hb_codepoint_t g) const { return g < first ? -1 : g <= last ? 0 : +1; } @@ -153,6 +229,7 @@ struct LookupSegmentArray { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && + hb_barrier () && first <= last && valuesZ.sanitize (c, base, last - first + 1)); } @@ -161,6 +238,7 @@ struct LookupSegmentArray { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && + hb_barrier () && first <= last && valuesZ.sanitize (c, base, last - first + 1, std::forward (ds)...)); } @@ -186,6 +264,14 @@ struct LookupFormat4 return v ? v->get_value (glyph_id, this) : nullptr; } + template + void collect_glyphs (set_t &glyphs) const + { + unsigned count = segments.get_length (); + for (unsigned i = 0; i < count; i++) + segments[i].collect_glyphs (glyphs); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -214,6 +300,14 @@ struct LookupSingle int cmp (hb_codepoint_t g) const { return glyph.cmp (g); } + template + void collect_glyphs (set_t &glyphs) const + { + if (glyph == DELETED_GLYPH) + return; + glyphs.add (glyph); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -243,6 +337,14 @@ struct LookupFormat6 return v ? &v->value : nullptr; } + template + void collect_glyphs (set_t &glyphs) const + { + unsigned count = entries.get_length (); + for (unsigned i = 0; i < count; i++) + entries[i].collect_glyphs (glyphs); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -274,6 +376,16 @@ struct LookupFormat8 &valueArrayZ[glyph_id - firstGlyph] : nullptr; } + template + void collect_glyphs (set_t &glyphs) const + { + if (unlikely (!glyphCount)) + return; + if (firstGlyph == DELETED_GLYPH) + return; + glyphs.add_range (firstGlyph, firstGlyph + glyphCount - 1); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -318,10 +430,21 @@ struct LookupFormat10 return v; } + template + void collect_glyphs (set_t &glyphs) const + { + if (unlikely (!glyphCount)) + return; + if (firstGlyph == DELETED_GLYPH) + return; + glyphs.add_range (firstGlyph, firstGlyph + glyphCount - 1); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && + hb_barrier () && valueSize <= 4 && valueArrayZ.sanitize (c, glyphCount * valueSize)); } @@ -345,11 +468,11 @@ struct Lookup const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const { switch (u.format) { - case 0: return u.format0.get_value (glyph_id, num_glyphs); - case 2: return u.format2.get_value (glyph_id); - case 4: return u.format4.get_value (glyph_id); - case 6: return u.format6.get_value (glyph_id); - case 8: return u.format8.get_value (glyph_id); + case 0: hb_barrier (); return u.format0.get_value (glyph_id, num_glyphs); + case 2: hb_barrier (); return u.format2.get_value (glyph_id); + case 4: hb_barrier (); return u.format4.get_value (glyph_id); + case 6: hb_barrier (); return u.format6.get_value (glyph_id); + case 8: hb_barrier (); return u.format8.get_value (glyph_id); default:return nullptr; } } @@ -358,13 +481,27 @@ struct Lookup { switch (u.format) { /* Format 10 cannot return a pointer. */ - case 10: return u.format10.get_value_or_null (glyph_id); + case 10: hb_barrier (); return u.format10.get_value_or_null (glyph_id); default: const T *v = get_value (glyph_id, num_glyphs); return v ? *v : Null (T); } } + template + void collect_glyphs (set_t &glyphs, unsigned int num_glyphs) const + { + switch (u.format) { + case 0: hb_barrier (); u.format0.collect_glyphs (glyphs, num_glyphs); return; + case 2: hb_barrier (); u.format2.collect_glyphs (glyphs); return; + case 4: hb_barrier (); u.format4.collect_glyphs (glyphs); return; + case 6: hb_barrier (); u.format6.collect_glyphs (glyphs); return; + case 8: hb_barrier (); u.format8.collect_glyphs (glyphs); return; + case 10: hb_barrier (); u.format10.collect_glyphs (glyphs); return; + default:return; + } + } + typename T::type get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs, unsigned int outOfRange) const @@ -377,13 +514,14 @@ struct Lookup { TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return_trace (false); + hb_barrier (); switch (u.format) { - case 0: return_trace (u.format0.sanitize (c)); - case 2: return_trace (u.format2.sanitize (c)); - case 4: return_trace (u.format4.sanitize (c)); - case 6: return_trace (u.format6.sanitize (c)); - case 8: return_trace (u.format8.sanitize (c)); - case 10: return_trace (u.format10.sanitize (c)); + case 0: hb_barrier (); return_trace (u.format0.sanitize (c)); + case 2: hb_barrier (); return_trace (u.format2.sanitize (c)); + case 4: hb_barrier (); return_trace (u.format4.sanitize (c)); + case 6: hb_barrier (); return_trace (u.format6.sanitize (c)); + case 8: hb_barrier (); return_trace (u.format8.sanitize (c)); + case 10: hb_barrier (); return_trace (u.format10.sanitize (c)); default:return_trace (true); } } @@ -391,12 +529,13 @@ struct Lookup { TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return_trace (false); + hb_barrier (); switch (u.format) { - case 0: return_trace (u.format0.sanitize (c, base)); - case 2: return_trace (u.format2.sanitize (c, base)); - case 4: return_trace (u.format4.sanitize (c, base)); - case 6: return_trace (u.format6.sanitize (c, base)); - case 8: return_trace (u.format8.sanitize (c, base)); + case 0: hb_barrier (); return_trace (u.format0.sanitize (c, base)); + case 2: hb_barrier (); return_trace (u.format2.sanitize (c, base)); + case 4: hb_barrier (); return_trace (u.format4.sanitize (c, base)); + case 6: hb_barrier (); return_trace (u.format6.sanitize (c, base)); + case 8: hb_barrier (); return_trace (u.format8.sanitize (c, base)); case 10: return_trace (false); /* We don't support format10 here currently. */ default:return_trace (true); } @@ -417,8 +556,6 @@ struct Lookup }; DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1 (AAT, Lookup, 2); -enum { DELETED_GLYPH = 0xFFFF }; - /* * (Extended) State Table */ @@ -426,7 +563,8 @@ enum { DELETED_GLYPH = 0xFFFF }; template struct Entry { - bool sanitize (hb_sanitize_context_t *c, unsigned int count) const + // This does seem like it's ever called. + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); /* Note, we don't recurse-sanitize data because we don't access it. @@ -454,7 +592,8 @@ struct Entry template <> struct Entry { - bool sanitize (hb_sanitize_context_t *c, unsigned int count /*XXX Unused?*/) const + // This does seem like it's ever called. + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); @@ -467,6 +606,14 @@ struct Entry DEFINE_SIZE_STATIC (4); }; +enum Class +{ + CLASS_END_OF_TEXT = 0, + CLASS_OUT_OF_BOUNDS = 1, + CLASS_DELETED_GLYPH = 2, + CLASS_END_OF_LINE = 3, +}; + template struct StateTable { @@ -479,21 +626,24 @@ struct StateTable STATE_START_OF_TEXT = 0, STATE_START_OF_LINE = 1, }; - enum Class + + template + void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const { - CLASS_END_OF_TEXT = 0, - CLASS_OUT_OF_BOUNDS = 1, - CLASS_DELETED_GLYPH = 2, - CLASS_END_OF_LINE = 3, - }; + (this+classTable).collect_glyphs (glyphs, num_glyphs); + } int new_state (unsigned int newState) const { return Types::extended ? newState : ((int) newState - (int) stateArrayTable) / (int) nClasses; } - unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const + template + unsigned int get_class (hb_codepoint_t glyph_id, + unsigned int num_glyphs, + const set_t &glyphs) const { if (unlikely (glyph_id == DELETED_GLYPH)) return CLASS_DELETED_GLYPH; - return (this+classTable).get_class (glyph_id, num_glyphs, 1); + if (!glyphs[glyph_id]) return CLASS_OUT_OF_BOUNDS; + return (this+classTable).get_class (glyph_id, num_glyphs, CLASS_OUT_OF_BOUNDS); } const Entry *get_entries () const @@ -502,7 +652,7 @@ struct StateTable const Entry &get_entry (int state, unsigned int klass) const { if (unlikely (klass >= nClasses)) - klass = StateTable::CLASS_OUT_OF_BOUNDS; + klass = CLASS_OUT_OF_BOUNDS; const HBUSHORT *states = (this+stateArrayTable).arrayZ; const Entry *entries = (this+entryTable).arrayZ; @@ -518,6 +668,7 @@ struct StateTable { TRACE_SANITIZE (this); if (unlikely (!(c->check_struct (this) && + hb_barrier () && nClasses >= 4 /* Ensure pre-defined classes fit. */ && classTable.sanitize (c, this)))) return_trace (false); @@ -644,6 +795,15 @@ struct ClassTable { return get_class (glyph_id, outOfRange); } + + template + void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const + { + for (unsigned i = 0; i < classArray.len; i++) + if (classArray.arrayZ[i] != CLASS_OUT_OF_BOUNDS) + glyphs.add (firstGlyph + i); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -657,6 +817,38 @@ struct ClassTable DEFINE_SIZE_ARRAY (4, classArray); }; +struct SubtableGlyphCoverage +{ + bool sanitize (hb_sanitize_context_t *c, unsigned subtable_count) const + { + TRACE_SANITIZE (this); + + if (unlikely (!c->check_array (&subtableOffsets, subtable_count))) + return_trace (false); + + unsigned bytes = (c->get_num_glyphs () + CHAR_BIT - 1) / CHAR_BIT; + for (unsigned i = 0; i < subtable_count; i++) + { + uint32_t offset = (uint32_t) subtableOffsets[i]; + if (offset == 0 || offset == 0xFFFFFFFF) + continue; + if (unlikely (!subtableOffsets[i].sanitize (c, this, bytes))) + return_trace (false); + } + + return_trace (true); + } + protected: + UnsizedArrayOf>> subtableOffsets; + /* Array of offsets from the beginning of the + * subtable glyph coverage table to the glyph + * coverage bitfield for a given subtable; there + * is one offset for each subtable in the chain */ + /* UnsizedArrayOf coverageBitfields; *//* The individual coverage bitfields. */ + public: + DEFINE_SIZE_ARRAY (0, subtableOffsets); +}; + struct ObsoleteTypes { static constexpr bool extended = false; @@ -733,24 +925,60 @@ struct StateTableDriver using EntryT = Entry; StateTableDriver (const StateTableT &machine_, - hb_buffer_t *buffer_, hb_face_t *face_) : machine (machine_), - buffer (buffer_), num_glyphs (face_->get_num_glyphs ()) {} template - void drive (context_t *c) + bool is_idempotent_on_all_out_of_bounds (context_t *c, hb_aat_apply_context_t *ac) + { + const auto entry = machine.get_entry (StateTableT::STATE_START_OF_TEXT, CLASS_OUT_OF_BOUNDS); + return !c->is_actionable (ac->buffer, this, entry) && + machine.new_state (entry.newState) == StateTableT::STATE_START_OF_TEXT; + } + + template + void drive (context_t *c, hb_aat_apply_context_t *ac) { + hb_buffer_t *buffer = ac->buffer; + if (!c->in_place) buffer->clear_output (); int state = StateTableT::STATE_START_OF_TEXT; + // If there's only one range, we already checked the flag. + auto *last_range = ac->range_flags && (ac->range_flags->length > 1) ? &(*ac->range_flags)[0] : nullptr; for (buffer->idx = 0; buffer->successful;) { - unsigned int klass = buffer->idx < buffer->len ? - machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) : - (unsigned) StateTableT::CLASS_END_OF_TEXT; + /* This block is copied in NoncontextualSubtable::apply. Keep in sync. */ + if (last_range) + { + auto *range = last_range; + if (buffer->idx < buffer->len) + { + unsigned cluster = buffer->cur().cluster; + while (cluster < range->cluster_first) + range--; + while (cluster > range->cluster_last) + range++; + + + last_range = range; + } + if (!(range->flags & ac->subtable_flags)) + { + if (buffer->idx == buffer->len || unlikely (!buffer->successful)) + break; + + state = StateTableT::STATE_START_OF_TEXT; + (void) buffer->next_glyph (); + continue; + } + } + + unsigned int klass = likely (buffer->idx < buffer->len) ? + machine.get_class (buffer->cur().codepoint, num_glyphs, ac->machine_glyph_set) : + (unsigned) CLASS_END_OF_TEXT; DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx); const EntryT &entry = machine.get_entry (state, klass); const int next_state = machine.new_state (entry.newState); @@ -783,46 +1011,44 @@ struct StateTableDriver * * https://github.com/harfbuzz/harfbuzz/issues/2860 */ - const EntryT *wouldbe_entry; - bool safe_to_break = - /* 1. */ - !c->is_actionable (this, entry) - && - /* 2. */ - ( - /* 2a. */ - state == StateTableT::STATE_START_OF_TEXT - || - /* 2b. */ - ( - (entry.flags & context_t::DontAdvance) && - next_state == StateTableT::STATE_START_OF_TEXT - ) - || - /* 2c. */ - ( - wouldbe_entry = &machine.get_entry (StateTableT::STATE_START_OF_TEXT, klass) - , - /* 2c'. */ - !c->is_actionable (this, *wouldbe_entry) - && - /* 2c". */ - ( - next_state == machine.new_state (wouldbe_entry->newState) - && - (entry.flags & context_t::DontAdvance) == (wouldbe_entry->flags & context_t::DontAdvance) - ) - ) - ) - && - /* 3. */ - !c->is_actionable (this, machine.get_entry (state, StateTableT::CLASS_END_OF_TEXT)) - ; - - if (!safe_to_break && buffer->backtrack_len () && buffer->idx < buffer->len) + + const auto is_safe_to_break_extra = [&]() + { + /* 2c. */ + const auto &wouldbe_entry = machine.get_entry(StateTableT::STATE_START_OF_TEXT, klass); + + /* 2c'. */ + if (c->is_actionable (buffer, this, wouldbe_entry)) + return false; + + /* 2c". */ + return next_state == machine.new_state(wouldbe_entry.newState) + && (entry.flags & context_t::DontAdvance) == (wouldbe_entry.flags & context_t::DontAdvance); + }; + + const auto is_safe_to_break = [&]() + { + /* 1. */ + if (c->is_actionable (buffer, this, entry)) + return false; + + /* 2. */ + // This one is meh, I know... + const auto ok = + state == StateTableT::STATE_START_OF_TEXT + || ((entry.flags & context_t::DontAdvance) && next_state == StateTableT::STATE_START_OF_TEXT) + || is_safe_to_break_extra(); + if (!ok) + return false; + + /* 3. */ + return !c->is_actionable (buffer, this, machine.get_entry (state, CLASS_END_OF_TEXT)); + }; + + if (!is_safe_to_break () && buffer->backtrack_len () && buffer->idx < buffer->len) buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1); - c->transition (this, entry); + c->transition (buffer, this, entry); state = next_state; DEBUG_MSG (APPLY, nullptr, "s%d", state); @@ -840,46 +1066,10 @@ struct StateTableDriver public: const StateTableT &machine; - hb_buffer_t *buffer; unsigned int num_glyphs; }; -struct ankr; - -struct hb_aat_apply_context_t : - hb_dispatch_context_t -{ - const char *get_name () { return "APPLY"; } - template - return_t dispatch (const T &obj) { return obj.apply (this); } - static return_t default_return_value () { return false; } - bool stop_sublookup_iteration (return_t r) const { return r; } - - const hb_ot_shape_plan_t *plan; - hb_font_t *font; - hb_face_t *face; - hb_buffer_t *buffer; - hb_sanitize_context_t sanitizer; - const ankr *ankr_table; - const OT::GDEF *gdef_table; - - /* Unused. For debug tracing only. */ - unsigned int lookup_index; - - HB_INTERNAL hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_, - hb_font_t *font_, - hb_buffer_t *buffer_, - hb_blob_t *blob = const_cast (&Null (hb_blob_t))); - - HB_INTERNAL ~hb_aat_apply_context_t (); - - HB_INTERNAL void set_ankr_table (const AAT::ankr *ankr_table_); - - void set_lookup_index (unsigned int i) { lookup_index = i; } -}; - - } /* namespace AAT */ diff --git a/libs/harfbuzz/src/hb-aat-layout-feat-table.hh b/libs/harfbuzz/src/hb-aat-layout-feat-table.hh index 815a1fd2a..4fbec332e 100644 --- a/libs/harfbuzz/src/hb-aat-layout-feat-table.hh +++ b/libs/harfbuzz/src/hb-aat-layout-feat-table.hh @@ -138,6 +138,7 @@ struct FeatureName { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && + hb_barrier () && (base+settingTableZ).sanitize (c, nSettings))); } @@ -200,6 +201,7 @@ struct feat { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && + hb_barrier () && version.major == 1 && namesZ.sanitize (c, featureNameCount, this))); } diff --git a/libs/harfbuzz/src/hb-aat-layout-just-table.hh b/libs/harfbuzz/src/hb-aat-layout-just-table.hh index 8fd3990f8..9531b5e4b 100644 --- a/libs/harfbuzz/src/hb-aat-layout-just-table.hh +++ b/libs/harfbuzz/src/hb-aat-layout-just-table.hh @@ -185,15 +185,16 @@ struct ActionSubrecord TRACE_SANITIZE (this); if (unlikely (!c->check_struct (this))) return_trace (false); + hb_barrier (); switch (u.header.actionType) { - case 0: return_trace (u.decompositionAction.sanitize (c)); - case 1: return_trace (u.unconditionalAddGlyphAction.sanitize (c)); - case 2: return_trace (u.conditionalAddGlyphAction.sanitize (c)); - // case 3: return_trace (u.stretchGlyphAction.sanitize (c)); - case 4: return_trace (u.decompositionAction.sanitize (c)); - case 5: return_trace (u.decompositionAction.sanitize (c)); + case 0: hb_barrier (); return_trace (u.decompositionAction.sanitize (c)); + case 1: hb_barrier (); return_trace (u.unconditionalAddGlyphAction.sanitize (c)); + case 2: hb_barrier (); return_trace (u.conditionalAddGlyphAction.sanitize (c)); + // case 3: hb_barrier (); return_trace (u.stretchGlyphAction.sanitize (c)); + case 4: hb_barrier (); return_trace (u.decompositionAction.sanitize (c)); + case 5: hb_barrier (); return_trace (u.decompositionAction.sanitize (c)); default: return_trace (true); } } @@ -220,6 +221,7 @@ struct PostcompensationActionChain TRACE_SANITIZE (this); if (unlikely (!c->check_struct (this))) return_trace (false); + hb_barrier (); unsigned int offset = min_size; for (unsigned int i = 0; i < count; i++) @@ -389,6 +391,7 @@ struct just TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && + hb_barrier () && version.major == 1 && horizData.sanitize (c, this, this) && vertData.sanitize (c, this, this))); diff --git a/libs/harfbuzz/src/hb-aat-layout-kerx-table.hh b/libs/harfbuzz/src/hb-aat-layout-kerx-table.hh index 995492cd5..c01c31d73 100644 --- a/libs/harfbuzz/src/hb-aat-layout-kerx-table.hh +++ b/libs/harfbuzz/src/hb-aat-layout-kerx-table.hh @@ -30,6 +30,7 @@ #include "hb-kern.hh" #include "hb-aat-layout-ankr-table.hh" +#include "hb-set-digest.hh" /* * kerx -- Extended Kerning @@ -54,6 +55,7 @@ kerxTupleKern (int value, unsigned int offset = value; const FWORD *pv = &StructAtOffset (base, offset); if (unlikely (!c->sanitizer.check_array (pv, tupleCount))) return 0; + hb_barrier (); return *pv; } @@ -81,7 +83,7 @@ struct KernPair return_trace (c->check_struct (this)); } - protected: + public: HBGlyphID16 left; HBGlyphID16 right; FWORD value; @@ -105,10 +107,14 @@ struct KerxSubTableFormat0 TRACE_APPLY (this); if (!c->plan->requested_kerning) - return false; + return_trace (false); if (header.coverage & header.Backwards) - return false; + return_trace (false); + + if (!(c->buffer_digest.may_have (c->left_set) && + c->buffer_digest.may_have (c->right_set))) + return_trace (false); accelerator_t accel (*this, c); hb_kern_machine_t machine (accel, header.coverage & header.CrossStream); @@ -117,6 +123,16 @@ struct KerxSubTableFormat0 return_trace (true); } + template + void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const + { + for (const KernPair& pair : pairs) + { + left_set.add (pair.left); + right_set.add (pair.right); + } + } + struct accelerator_t { const KerxSubTableFormat0 &table; @@ -127,7 +143,10 @@ struct KerxSubTableFormat0 table (table_), c (c_) {} int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const - { return table.get_kerning (left, right, c); } + { + if (!c->left_set[left] || !c->right_set[right]) return 0; + return table.get_kerning (left, right, c); + } }; @@ -227,13 +246,14 @@ struct KerxSubTableFormat1 depth (0), crossStream (table->header.coverage & table->header.CrossStream) {} - bool is_actionable (StateTableDriver *driver HB_UNUSED, + bool is_actionable (hb_buffer_t *buffer HB_UNUSED, + StateTableDriver *driver HB_UNUSED, const Entry &entry) { return Format1EntryT::performAction (entry); } - void transition (StateTableDriver *driver, + void transition (hb_buffer_t *buffer, + StateTableDriver *driver, const Entry &entry) { - hb_buffer_t *buffer = driver->buffer; unsigned int flags = entry.flags; if (flags & Format1EntryT::Reset) @@ -259,6 +279,7 @@ struct KerxSubTableFormat1 depth = 0; return; } + hb_barrier (); hb_mask_t kern_mask = c->plan->kern_mask; @@ -349,8 +370,14 @@ struct KerxSubTableFormat1 driver_context_t dc (this, c); - StateTableDriver driver (machine, c->buffer, c->font->face); - driver.drive (&dc); + StateTableDriver driver (machine, c->font->face); + + if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) && + !(c->buffer_digest.may_have (c->left_set) && + c->buffer_digest.may_have (c->right_set))) + return_trace (false); + + driver.drive (&dc, c); return_trace (true); } @@ -363,12 +390,21 @@ struct KerxSubTableFormat1 machine.sanitize (c))); } + template + void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const + { + set_t set; + machine.collect_glyphs (set, num_glyphs); + left_set.union_ (set); + right_set.union_ (set); + } + protected: KernSubTableHeader header; StateTable machine; NNOffsetTo, HBUINT> kernAction; public: - DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 5 * sizeof (HBUINT)); + DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + (StateTable::static_size + HBUINT::static_size)); }; template @@ -389,6 +425,7 @@ struct KerxSubTableFormat2 kern_idx = Types::offsetToIndex (kern_idx, this, arrayZ.arrayZ); const FWORD *v = &arrayZ[kern_idx]; if (unlikely (!v->sanitize (&c->sanitizer))) return 0; + hb_barrier (); return kerxTupleKern (*v, header.tuple_count (), this, c); } @@ -398,10 +435,14 @@ struct KerxSubTableFormat2 TRACE_APPLY (this); if (!c->plan->requested_kerning) - return false; + return_trace (false); if (header.coverage & header.Backwards) - return false; + return_trace (false); + + if (!(c->buffer_digest.may_have (c->left_set) && + c->buffer_digest.may_have (c->right_set))) + return_trace (false); accelerator_t accel (*this, c); hb_kern_machine_t machine (accel, header.coverage & header.CrossStream); @@ -410,6 +451,13 @@ struct KerxSubTableFormat2 return_trace (true); } + template + void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const + { + (this+leftClassTable).collect_glyphs (left_set, num_glyphs); + (this+rightClassTable).collect_glyphs (right_set, num_glyphs); + } + struct accelerator_t { const KerxSubTableFormat2 &table; @@ -420,7 +468,10 @@ struct KerxSubTableFormat2 table (table_), c (c_) {} int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const - { return table.get_kerning (left, right, c); } + { + if (!c->left_set[left] || !c->right_set[right]) return 0; + return table.get_kerning (left, right, c); + } }; bool sanitize (hb_sanitize_context_t *c) const @@ -429,6 +480,7 @@ struct KerxSubTableFormat2 return_trace (likely (c->check_struct (this) && leftClassTable.sanitize (c, this) && rightClassTable.sanitize (c, this) && + hb_barrier () && c->check_range (this, array))); } @@ -489,14 +541,14 @@ struct KerxSubTableFormat4 mark_set (false), mark (0) {} - bool is_actionable (StateTableDriver *driver HB_UNUSED, + bool is_actionable (hb_buffer_t *buffer HB_UNUSED, + StateTableDriver *driver HB_UNUSED, const Entry &entry) { return entry.data.ankrActionIndex != 0xFFFF; } - void transition (StateTableDriver *driver, + void transition (hb_buffer_t *buffer, + StateTableDriver *driver, const Entry &entry) { - hb_buffer_t *buffer = driver->buffer; - if (mark_set && entry.data.ankrActionIndex != 0xFFFF && buffer->idx < buffer->len) { hb_glyph_position_t &o = buffer->cur_pos(); @@ -509,6 +561,7 @@ struct KerxSubTableFormat4 double the ankrActionIndex to get the correct offset here. */ const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex * 2]; if (!c->sanitizer.check_array (data, 2)) return; + hb_barrier (); unsigned int markControlPoint = *data++; unsigned int currControlPoint = *data++; hb_position_t markX = 0; @@ -537,6 +590,7 @@ struct KerxSubTableFormat4 double the ankrActionIndex to get the correct offset here. */ const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex * 2]; if (!c->sanitizer.check_array (data, 2)) return; + hb_barrier (); unsigned int markAnchorPoint = *data++; unsigned int currAnchorPoint = *data++; const Anchor &markAnchor = c->ankr_table->get_anchor (c->buffer->info[mark].codepoint, @@ -557,6 +611,7 @@ struct KerxSubTableFormat4 by 4 to get the correct offset for the given action. */ const FWORD *data = (const FWORD *) &ankrData[entry.data.ankrActionIndex * 4]; if (!c->sanitizer.check_array (data, 4)) return; + hb_barrier (); int markX = *data++; int markY = *data++; int currX = *data++; @@ -593,8 +648,14 @@ struct KerxSubTableFormat4 driver_context_t dc (this, c); - StateTableDriver driver (machine, c->buffer, c->font->face); - driver.drive (&dc); + StateTableDriver driver (machine, c->font->face); + + if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) && + !(c->buffer_digest.may_have (c->left_set) && + c->buffer_digest.may_have (c->right_set))) + return_trace (false); + + driver.drive (&dc, c); return_trace (true); } @@ -607,12 +668,21 @@ struct KerxSubTableFormat4 machine.sanitize (c))); } + template + void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const + { + set_t set; + machine.collect_glyphs (set, num_glyphs); + left_set.union_ (set); + right_set.union_ (set); + } + protected: KernSubTableHeader header; StateTable machine; HBUINT32 flags; public: - DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 20); + DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + (StateTable::static_size + HBUINT32::static_size)); }; template @@ -631,7 +701,7 @@ struct KerxSubTableFormat6 unsigned int num_glyphs = c->sanitizer.get_num_glyphs (); if (is_long ()) { - const typename U::Long &t = u.l; + const auto &t = u.l; unsigned int l = (this+t.rowIndexTable).get_value_or_null (left, num_glyphs); unsigned int r = (this+t.columnIndexTable).get_value_or_null (right, num_glyphs); unsigned int offset = l + r; @@ -639,16 +709,18 @@ struct KerxSubTableFormat6 if (unlikely (hb_unsigned_mul_overflows (offset, sizeof (FWORD32)))) return 0; const FWORD32 *v = &StructAtOffset (&(this+t.array), offset * sizeof (FWORD32)); if (unlikely (!v->sanitize (&c->sanitizer))) return 0; + hb_barrier (); return kerxTupleKern (*v, header.tuple_count (), &(this+vector), c); } else { - const typename U::Short &t = u.s; + const auto &t = u.s; unsigned int l = (this+t.rowIndexTable).get_value_or_null (left, num_glyphs); unsigned int r = (this+t.columnIndexTable).get_value_or_null (right, num_glyphs); unsigned int offset = l + r; const FWORD *v = &StructAtOffset (&(this+t.array), offset * sizeof (FWORD)); if (unlikely (!v->sanitize (&c->sanitizer))) return 0; + hb_barrier (); return kerxTupleKern (*v, header.tuple_count (), &(this+vector), c); } } @@ -658,10 +730,14 @@ struct KerxSubTableFormat6 TRACE_APPLY (this); if (!c->plan->requested_kerning) - return false; + return_trace (false); if (header.coverage & header.Backwards) - return false; + return_trace (false); + + if (!(c->buffer_digest.may_have (c->left_set) && + c->buffer_digest.may_have (c->right_set))) + return_trace (false); accelerator_t accel (*this, c); hb_kern_machine_t machine (accel, header.coverage & header.CrossStream); @@ -674,6 +750,7 @@ struct KerxSubTableFormat6 { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && + hb_barrier () && (is_long () ? ( u.l.rowIndexTable.sanitize (c, this) && @@ -688,6 +765,23 @@ struct KerxSubTableFormat6 c->check_range (this, vector)))); } + template + void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const + { + if (is_long ()) + { + const auto &t = u.l; + (this+t.rowIndexTable).collect_glyphs (left_set, num_glyphs); + (this+t.columnIndexTable).collect_glyphs (right_set, num_glyphs); + } + else + { + const auto &t = u.s; + (this+t.rowIndexTable).collect_glyphs (left_set, num_glyphs); + (this+t.columnIndexTable).collect_glyphs (right_set, num_glyphs); + } + } + struct accelerator_t { const KerxSubTableFormat6 &table; @@ -698,7 +792,10 @@ struct KerxSubTableFormat6 table (table_), c (c_) {} int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const - { return table.get_kerning (left, right, c); } + { + if (!c->left_set[left] || !c->right_set[right]) return 0; + return table.get_kerning (left, right, c); + } }; protected: @@ -784,12 +881,27 @@ struct KerxSubTable } } + template + void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const + { + unsigned int subtable_type = get_type (); + switch (subtable_type) { + case 0: u.format0.collect_glyphs (left_set, right_set, num_glyphs); return; + case 1: u.format1.collect_glyphs (left_set, right_set, num_glyphs); return; + case 2: u.format2.collect_glyphs (left_set, right_set, num_glyphs); return; + case 4: u.format4.collect_glyphs (left_set, right_set, num_glyphs); return; + case 6: u.format6.collect_glyphs (left_set, right_set, num_glyphs); return; + default: return; + } + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (!u.header.sanitize (c) || - u.header.length <= u.header.static_size || - !c->check_range (this, u.header.length)) + if (!(u.header.sanitize (c) && + hb_barrier () && + u.header.length >= u.header.static_size && + c->check_range (this, u.header.length))) return_trace (false); return_trace (dispatch (c)); @@ -813,6 +925,8 @@ struct KerxSubTable * The 'kerx' Table */ +using kern_accelerator_data_t = hb_vector_t>; + template struct KerxTable { @@ -829,6 +943,9 @@ struct KerxTable { if (st->get_type () == 1) return true; + + // TODO: What about format 4? What's this API used for anyway? + st = &StructAfter (*st); } return false; @@ -867,8 +984,16 @@ struct KerxTable return v; } - bool apply (AAT::hb_aat_apply_context_t *c) const + bool apply (AAT::hb_aat_apply_context_t *c, + const kern_accelerator_data_t *accel_data = nullptr) const { + c->buffer->unsafe_to_concat (); + + if (c->buffer->len < HB_AAT_BUFFER_DIGEST_THRESHOLD) + c->buffer_digest = c->buffer->digest (); + else + c->buffer_digest = hb_set_digest_t::full (); + typedef typename T::SubTable SubTable; bool ret = false; @@ -889,7 +1014,7 @@ struct KerxTable reverse = bool (st->u.header.coverage & st->u.header.Backwards) != HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction); - if (!c->buffer->message (c->font, "start subtable %d", c->lookup_index)) + if (!c->buffer->message (c->font, "start subtable %u", c->lookup_index)) goto skip; if (!seenCrossStream && @@ -912,6 +1037,16 @@ struct KerxTable if (reverse) c->buffer->reverse (); + if (accel_data) + { + c->left_set = (*accel_data)[i].first; + c->right_set = (*accel_data)[i].second; + } + else + { + c->left_set = c->right_set = hb_set_digest_t::full (); + } + { /* See comment in sanitize() for conditional here. */ hb_sanitize_with_object_t with (&c->sanitizer, i < count - 1 ? st : (const SubTable *) nullptr); @@ -921,7 +1056,7 @@ struct KerxTable if (reverse) c->buffer->reverse (); - (void) c->buffer->message (c->font, "end subtable %d", c->lookup_index); + (void) c->buffer->message (c->font, "end subtable %u", c->lookup_index); skip: st = &StructAfter (*st); @@ -934,9 +1069,10 @@ struct KerxTable bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (unlikely (!thiz()->version.sanitize (c) || - (unsigned) thiz()->version < (unsigned) T::minVersion || - !thiz()->tableCount.sanitize (c))) + if (unlikely (!(thiz()->version.sanitize (c) && + hb_barrier () && + (unsigned) thiz()->version >= (unsigned) T::minVersion && + thiz()->tableCount.sanitize (c)))) return_trace (false); typedef typename T::SubTable SubTable; @@ -947,6 +1083,7 @@ struct KerxTable { if (unlikely (!st->u.header.sanitize (c))) return_trace (false); + hb_barrier (); /* OpenType kern table has 2-byte subtable lengths. That's limiting. * MS implementation also only supports one subtable, of format 0, * anyway. Certain versions of some fonts, like Calibry, contain @@ -962,8 +1099,61 @@ struct KerxTable st = &StructAfter (*st); } + unsigned majorVersion = thiz()->version; + if (sizeof (thiz()->version) == 4) + majorVersion = majorVersion >> 16; + if (majorVersion >= 3) + { + const SubtableGlyphCoverage *coverage = (const SubtableGlyphCoverage *) st; + if (!coverage->sanitize (c, count)) + return_trace (false); + } + return_trace (true); } + + kern_accelerator_data_t create_accelerator_data (unsigned num_glyphs) const + { + kern_accelerator_data_t accel_data; + + typedef typename T::SubTable SubTable; + + const SubTable *st = &thiz()->firstSubTable; + unsigned int count = thiz()->tableCount; + for (unsigned int i = 0; i < count; i++) + { + hb_set_digest_t left_set, right_set; + st->collect_glyphs (left_set, right_set, num_glyphs); + accel_data.push (hb_pair (left_set, right_set)); + st = &StructAfter (*st); + } + + return accel_data; + } + + struct accelerator_t + { + accelerator_t (hb_face_t *face) + { + hb_sanitize_context_t sc; + this->table = sc.reference_table (face); + this->accel_data = this->table->create_accelerator_data (face->get_num_glyphs ()); + } + ~accelerator_t () + { + this->table.destroy (); + } + + hb_blob_t *get_blob () const { return table.get_blob (); } + + bool apply (AAT::hb_aat_apply_context_t *c) const + { + return table->apply (c, &accel_data); + } + + hb_blob_ptr_t table; + kern_accelerator_data_t accel_data; + }; }; struct kerx : KerxTable @@ -992,8 +1182,10 @@ struct kerx : KerxTable DEFINE_SIZE_MIN (8); }; +struct kerx_accelerator_t : kerx::accelerator_t { + kerx_accelerator_t (hb_face_t *face) : kerx::accelerator_t (face) {} +}; } /* namespace AAT */ - #endif /* HB_AAT_LAYOUT_KERX_TABLE_HH */ diff --git a/libs/harfbuzz/src/hb-aat-layout-morx-table.hh b/libs/harfbuzz/src/hb-aat-layout-morx-table.hh index aa4ad4cf3..d31834402 100644 --- a/libs/harfbuzz/src/hb-aat-layout-morx-table.hh +++ b/libs/harfbuzz/src/hb-aat-layout-morx-table.hh @@ -74,15 +74,16 @@ struct RearrangementSubtable ret (false), start (0), end (0) {} - bool is_actionable (StateTableDriver *driver HB_UNUSED, - const Entry &entry) + bool is_actionable (hb_buffer_t *buffer HB_UNUSED, + StateTableDriver *driver HB_UNUSED, + const Entry &entry) const { return (entry.flags & Verb) && start < end; } - void transition (StateTableDriver *driver, + void transition (hb_buffer_t *buffer, + StateTableDriver *driver, const Entry &entry) { - hb_buffer_t *buffer = driver->buffer; unsigned int flags = entry.flags; if (flags & MarkFirst) @@ -131,14 +132,14 @@ struct RearrangementSubtable hb_glyph_info_t *info = buffer->info; hb_glyph_info_t buf[4]; - memcpy (buf, info + start, l * sizeof (buf[0])); - memcpy (buf + 2, info + end - r, r * sizeof (buf[0])); + hb_memcpy (buf, info + start, l * sizeof (buf[0])); + hb_memcpy (buf + 2, info + end - r, r * sizeof (buf[0])); if (l != r) memmove (info + start + r, info + start + l, (end - start - l - r) * sizeof (buf[0])); - memcpy (info + start, buf + 2, r * sizeof (buf[0])); - memcpy (info + end - l, buf, l * sizeof (buf[0])); + hb_memcpy (info + start, buf + 2, r * sizeof (buf[0])); + hb_memcpy (info + end - l, buf, l * sizeof (buf[0])); if (reverse_l) { buf[0] = info[end - 1]; @@ -168,8 +169,13 @@ struct RearrangementSubtable driver_context_t dc (this); - StateTableDriver driver (machine, c->buffer, c->face); - driver.drive (&dc); + StateTableDriver driver (machine, c->face); + + if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) && + !c->buffer_digest.may_have (c->machine_glyph_set)) + return_trace (false); + + driver.drive (&dc, c); return_trace (dc.ret); } @@ -180,10 +186,10 @@ struct RearrangementSubtable return_trace (machine.sanitize (c)); } - protected: + public: StateTable machine; public: - DEFINE_SIZE_STATIC (16); + DEFINE_SIZE_STATIC ((StateTable::static_size)); }; template @@ -223,21 +229,19 @@ struct ContextualSubtable table (table_), subs (table+table->substitutionTables) {} - bool is_actionable (StateTableDriver *driver, - const Entry &entry) + bool is_actionable (hb_buffer_t *buffer, + StateTableDriver *driver, + const Entry &entry) const { - hb_buffer_t *buffer = driver->buffer; - if (buffer->idx == buffer->len && !mark_set) return false; return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF; } - void transition (StateTableDriver *driver, + void transition (hb_buffer_t *buffer, + StateTableDriver *driver, const Entry &entry) { - hb_buffer_t *buffer = driver->buffer; - /* Looks like CoreText applies neither mark nor current substitution for * end-of-text if mark was not explicitly set. */ if (buffer->idx == buffer->len && !mark_set) @@ -259,13 +263,16 @@ struct ContextualSubtable unsigned int offset = entry.data.markIndex + buffer->info[mark].codepoint; const UnsizedArrayOf &subs_old = (const UnsizedArrayOf &) subs; replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)]; - if (!replacement->sanitize (&c->sanitizer) || !*replacement) + if (!(replacement->sanitize (&c->sanitizer) && + hb_barrier () && + *replacement)) replacement = nullptr; } if (replacement) { buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len)); buffer->info[mark].codepoint = *replacement; + c->buffer_digest.add (*replacement); if (has_glyph_classes) _hb_glyph_info_set_glyph_props (&buffer->info[mark], gdef.get_glyph_props (*replacement)); @@ -287,12 +294,15 @@ struct ContextualSubtable unsigned int offset = entry.data.currentIndex + buffer->info[idx].codepoint; const UnsizedArrayOf &subs_old = (const UnsizedArrayOf &) subs; replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)]; - if (!replacement->sanitize (&c->sanitizer) || !*replacement) + if (!(replacement->sanitize (&c->sanitizer) && + hb_barrier () && + *replacement)) replacement = nullptr; } if (replacement) { buffer->info[idx].codepoint = *replacement; + c->buffer_digest.add (*replacement); if (has_glyph_classes) _hb_glyph_info_set_glyph_props (&buffer->info[idx], gdef.get_glyph_props (*replacement)); @@ -315,7 +325,7 @@ struct ContextualSubtable bool has_glyph_classes; unsigned int mark; const ContextualSubtable *table; - const UnsizedListOfOffset16To, HBUINT, false> &subs; + const UnsizedListOfOffset16To, HBUINT, void, false> &subs; }; bool apply (hb_aat_apply_context_t *c) const @@ -324,8 +334,13 @@ struct ContextualSubtable driver_context_t dc (this, c); - StateTableDriver driver (machine, c->buffer, c->face); - driver.drive (&dc); + StateTableDriver driver (machine, c->face); + + if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) && + !c->buffer_digest.may_have (c->machine_glyph_set)) + return_trace (false); + + driver.drive (&dc, c); return_trace (dc.ret); } @@ -336,6 +351,7 @@ struct ContextualSubtable unsigned int num_entries = 0; if (unlikely (!machine.sanitize (c, &num_entries))) return_trace (false); + hb_barrier (); if (!Types::extended) return_trace (substitutionTables.sanitize (c, this, 0)); @@ -356,13 +372,14 @@ struct ContextualSubtable return_trace (substitutionTables.sanitize (c, this, num_lookups)); } - protected: + public: StateTable machine; - NNOffsetTo, HBUINT, false>, HBUINT> + protected: + NNOffsetTo, HBUINT, void, false>, HBUINT> substitutionTables; public: - DEFINE_SIZE_STATIC (20); + DEFINE_SIZE_STATIC ((StateTable::static_size + HBUINT::static_size)); }; @@ -459,16 +476,16 @@ struct LigatureSubtable ligature (table+table->ligature), match_length (0) {} - bool is_actionable (StateTableDriver *driver HB_UNUSED, - const Entry &entry) + bool is_actionable (hb_buffer_t *buffer HB_UNUSED, + StateTableDriver *driver HB_UNUSED, + const Entry &entry) const { return LigatureEntryT::performAction (entry); } - void transition (StateTableDriver *driver, + void transition (hb_buffer_t *buffer, + StateTableDriver *driver, const Entry &entry) { - hb_buffer_t *buffer = driver->buffer; - DEBUG_MSG (APPLY, nullptr, "Ligature transition at %u", buffer->idx); if (entry.flags & LigatureEntryT::SetComponent) { @@ -513,6 +530,7 @@ struct LigatureSubtable if (unlikely (!buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]))) return; if (unlikely (!actionData->sanitize (&c->sanitizer))) break; + hb_barrier (); action = *actionData; uint32_t uoffset = action & LigActionOffset; @@ -523,9 +541,10 @@ struct LigatureSubtable component_idx = Types::wordOffsetToIndex (component_idx, table, component.arrayZ); const HBUINT16 &componentData = component[component_idx]; if (unlikely (!componentData.sanitize (&c->sanitizer))) break; + hb_barrier (); ligature_idx += componentData; - DEBUG_MSG (APPLY, nullptr, "Action store %u last %u", + DEBUG_MSG (APPLY, nullptr, "Action store %d last %d", bool (action & LigActionStore), bool (action & LigActionLast)); if (action & (LigActionStore | LigActionLast)) @@ -533,6 +552,7 @@ struct LigatureSubtable ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ); const HBGlyphID16 &ligatureData = ligature[ligature_idx]; if (unlikely (!ligatureData.sanitize (&c->sanitizer))) break; + hb_barrier (); hb_codepoint_t lig = ligatureData; DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig); @@ -544,6 +564,7 @@ struct LigatureSubtable { DEBUG_MSG (APPLY, nullptr, "Skipping ligature component"); if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return; + buffer->cur().unicode_props() |= UPROPS_MASK_IGNORABLE; if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return; } @@ -576,8 +597,13 @@ struct LigatureSubtable driver_context_t dc (this, c); - StateTableDriver driver (machine, c->buffer, c->face); - driver.drive (&dc); + StateTableDriver driver (machine, c->face); + + if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) && + !c->buffer_digest.may_have (c->machine_glyph_set)) + return_trace (false); + + driver.drive (&dc, c); return_trace (dc.ret); } @@ -587,12 +613,14 @@ struct LigatureSubtable TRACE_SANITIZE (this); /* The rest of array sanitizations are done at run-time. */ return_trace (c->check_struct (this) && machine.sanitize (c) && + hb_barrier () && ligAction && component && ligature); } - protected: + public: StateTable machine; + protected: NNOffsetTo, HBUINT> ligAction; /* Offset to the ligature action table. */ NNOffsetTo, HBUINT> @@ -600,7 +628,7 @@ struct LigatureSubtable NNOffsetTo, HBUINT> ligature; /* Offset to the actual ligature lists. */ public: - DEFINE_SIZE_STATIC (28); + DEFINE_SIZE_STATIC ((StateTable::static_size + 3 * HBUINT::static_size)); }; template @@ -618,12 +646,32 @@ struct NoncontextualSubtable hb_glyph_info_t *info = c->buffer->info; unsigned int count = c->buffer->len; + // If there's only one range, we already checked the flag. + auto *last_range = c->range_flags && (c->range_flags->length > 1) ? &(*c->range_flags)[0] : nullptr; for (unsigned int i = 0; i < count; i++) { + /* This block copied from StateTableDriver::drive. Keep in sync. */ + if (last_range) + { + auto *range = last_range; + { + unsigned cluster = info[i].cluster; + while (cluster < range->cluster_first) + range--; + while (cluster > range->cluster_last) + range++; + + last_range = range; + } + if (!(range->flags & c->subtable_flags)) + continue; + } + const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs); if (replacement) { info[i].codepoint = *replacement; + c->buffer_digest.add (*replacement); if (has_glyph_classes) _hb_glyph_info_set_glyph_props (&info[i], gdef.get_glyph_props (*replacement)); @@ -725,16 +773,17 @@ struct InsertionSubtable mark (0), insertionAction (table+table->insertionAction) {} - bool is_actionable (StateTableDriver *driver HB_UNUSED, - const Entry &entry) + bool is_actionable (hb_buffer_t *buffer HB_UNUSED, + StateTableDriver *driver HB_UNUSED, + const Entry &entry) const { return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) && (entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF); } - void transition (StateTableDriver *driver, + void transition (hb_buffer_t *buffer, + StateTableDriver *driver, const Entry &entry) { - hb_buffer_t *buffer = driver->buffer; unsigned int flags = entry.flags; unsigned mark_loc = buffer->out_len; @@ -746,6 +795,7 @@ struct InsertionSubtable unsigned int start = entry.data.markedInsertIndex; const HBGlyphID16 *glyphs = &insertionAction[start]; if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0; + hb_barrier (); bool before = flags & MarkedInsertBefore; @@ -756,6 +806,9 @@ struct InsertionSubtable if (unlikely (!buffer->copy_glyph ())) return; /* TODO We ignore KashidaLike setting. */ if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return; + for (unsigned int i = 0; i < count; i++) + c->buffer_digest.add (glyphs[i]); + ret = true; if (buffer->idx < buffer->len && !before) buffer->skip_glyph (); @@ -774,6 +827,7 @@ struct InsertionSubtable unsigned int start = entry.data.currentInsertIndex; const HBGlyphID16 *glyphs = &insertionAction[start]; if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0; + hb_barrier (); bool before = flags & CurrentInsertBefore; @@ -819,8 +873,13 @@ struct InsertionSubtable driver_context_t dc (this, c); - StateTableDriver driver (machine, c->buffer, c->face); - driver.drive (&dc); + StateTableDriver driver (machine, c->face); + + if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) && + !c->buffer_digest.may_have (c->machine_glyph_set)) + return_trace (false); + + driver.drive (&dc, c); return_trace (dc.ret); } @@ -830,17 +889,19 @@ struct InsertionSubtable TRACE_SANITIZE (this); /* The rest of array sanitizations are done at run-time. */ return_trace (c->check_struct (this) && machine.sanitize (c) && + hb_barrier () && insertionAction); } - protected: + public: StateTable machine; + protected: NNOffsetTo, HBUINT> insertionAction; /* Byte offset from stateHeader to the start of * the insertion glyph table. */ public: - DEFINE_SIZE_STATIC (20); + DEFINE_SIZE_STATIC ((StateTable::static_size + HBUINT::static_size)); }; @@ -864,6 +925,89 @@ struct Feature DEFINE_SIZE_STATIC (12); }; + +struct hb_accelerate_subtables_context_t : + hb_dispatch_context_t +{ + struct hb_applicable_t + { + friend struct hb_accelerate_subtables_context_t; + friend struct hb_aat_layout_lookup_accelerator_t; + + public: + hb_set_digest_t digest; + + template + auto init_ (const T &obj_, unsigned num_glyphs, hb_priority<1>) HB_AUTO_RETURN + ( + obj_.machine.collect_glyphs (this->digest, num_glyphs) + ) + + template + void init_ (const T &obj_, unsigned num_glyphs, hb_priority<0>) + { + digest = digest.full (); + } + + template + void init (const T &obj_, unsigned num_glyphs) + { + init_ (obj_, num_glyphs, hb_prioritize); + } + }; + + /* Dispatch interface. */ + template + return_t dispatch (const T &obj) + { + hb_applicable_t *entry = &array[i++]; + + entry->init (obj, num_glyphs); + + return hb_empty_t (); + } + static return_t default_return_value () { return hb_empty_t (); } + + bool stop_sublookup_iteration (return_t r) const { return false; } + + hb_accelerate_subtables_context_t (hb_applicable_t *array_, unsigned num_glyphs_) : + hb_dispatch_context_t (), + array (array_), num_glyphs (num_glyphs_) {} + + hb_applicable_t *array; + unsigned num_glyphs; + unsigned i = 0; +}; + +struct hb_aat_layout_chain_accelerator_t +{ + template + static hb_aat_layout_chain_accelerator_t *create (const TChain &chain, unsigned num_glyphs) + { + unsigned count = chain.get_subtable_count (); + + unsigned size = sizeof (hb_aat_layout_chain_accelerator_t) - + HB_VAR_ARRAY * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t) + + count * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t); + + /* The following is a calloc because when we are collecting subtables, + * some of them might be invalid and hence not collect; as a result, + * we might not fill in all the count entries of the subtables array. + * Zeroing it allows the set digest to gatekeep it without having to + * initialize it further. */ + auto *thiz = (hb_aat_layout_chain_accelerator_t *) hb_calloc (1, size); + if (unlikely (!thiz)) + return nullptr; + + hb_accelerate_subtables_context_t c_accelerate_subtables (thiz->subtables, num_glyphs); + chain.dispatch (&c_accelerate_subtables); + + return thiz; + } + + hb_accelerate_subtables_context_t::hb_applicable_t subtables[HB_VAR_ARRAY]; +}; + template struct ChainSubtable { @@ -918,19 +1062,22 @@ struct ChainSubtable bool apply (hb_aat_apply_context_t *c) const { TRACE_APPLY (this); - hb_sanitize_with_object_t with (&c->sanitizer, this); + // Disabled for https://github.com/harfbuzz/harfbuzz/issues/4873 + //hb_sanitize_with_object_t with (&c->sanitizer, this); return_trace (dispatch (c)); } bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (!length.sanitize (c) || - length <= min_size || - !c->check_range (this, length)) + if (!(length.sanitize (c) && + hb_barrier () && + length >= min_size && + c->check_range (this, length))) return_trace (false); - hb_sanitize_with_object_t with (c, this); + // Disabled for https://github.com/harfbuzz/harfbuzz/issues/4873 + //hb_sanitize_with_object_t with (c, this); return_trace (dispatch (c)); } @@ -954,6 +1101,8 @@ struct Chain { typedef typename Types::HBUINT HBUINT; + unsigned get_subtable_count () const { return subtableCount; } + hb_mask_t compile_flags (const hb_aat_map_builder_t *map) const { hb_mask_t flags = defaultFlags; @@ -968,7 +1117,7 @@ struct Chain // Check whether this type/setting pair was requested in the map, and if so, apply its flags. // (The search here only looks at the type and setting fields of feature_info_t.) hb_aat_map_builder_t::feature_info_t info = { type, setting, false, 0 }; - if (map->features.bsearch (info)) + if (map->current_features.bsearch (info)) { flags &= feature.disableFlags; flags |= feature.enableFlags; @@ -995,7 +1144,7 @@ struct Chain } void apply (hb_aat_apply_context_t *c, - hb_mask_t flags) const + const hb_aat_layout_chain_accelerator_t *accel) const { const ChainSubtable *subtable = &StructAfter> (featureZ.as_array (featureCount)); unsigned int count = subtableCount; @@ -1003,8 +1152,11 @@ struct Chain { bool reverse; - if (!(subtable->subFeatureFlags & flags)) + if (hb_none (hb_iter (c->range_flags) | + hb_map ([&subtable] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable->subFeatureFlags & (_.flags); }))) goto skip; + c->subtable_flags = subtable->subFeatureFlags; + c->machine_glyph_set = accel ? accel->subtables[i].digest : hb_set_digest_t::full (); if (!(subtable->get_coverage() & ChainSubtable::AllDirections) && HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) != @@ -1043,7 +1195,7 @@ struct Chain bool (subtable->get_coverage () & ChainSubtable::Backwards) != HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction); - if (!c->buffer->message (c->font, "start chainsubtable %d", c->lookup_index)) + if (!c->buffer->message (c->font, "start chainsubtable %u", c->lookup_index)) goto skip; if (reverse) @@ -1054,7 +1206,7 @@ struct Chain if (reverse) c->buffer->reverse (); - (void) c->buffer->message (c->font, "end chainsubtable %d", c->lookup_index); + (void) c->buffer->message (c->font, "end chainsubtable %u", c->lookup_index); if (unlikely (!c->buffer->successful)) return; @@ -1066,12 +1218,28 @@ struct Chain unsigned int get_size () const { return length; } - bool sanitize (hb_sanitize_context_t *c, unsigned int version HB_UNUSED) const + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const + { + const ChainSubtable *subtable = &StructAfter> (featureZ.as_array (featureCount)); + unsigned int count = subtableCount; + for (unsigned int i = 0; i < count; i++) + { + typename context_t::return_t ret = subtable->dispatch (c, std::forward (ds)...); + if (c->stop_sublookup_iteration (ret)) + return ret; + subtable = &StructAfter> (*subtable); + } + return c->default_return_value (); + } + + bool sanitize (hb_sanitize_context_t *c, unsigned int version) const { TRACE_SANITIZE (this); - if (!length.sanitize (c) || - length < min_size || - !c->check_range (this, length)) + if (!(length.sanitize (c) && + hb_barrier () && + length >= min_size && + c->check_range (this, length))) return_trace (false); if (!c->check_array (featureZ.arrayZ, featureCount)) @@ -1083,9 +1251,17 @@ struct Chain { if (!subtable->sanitize (c)) return_trace (false); + hb_barrier (); subtable = &StructAfter> (*subtable); } + if (version >= 3) + { + const SubtableGlyphCoverage *coverage = (const SubtableGlyphCoverage *) subtable; + if (!coverage->sanitize (c, count)) + return_trace (false); + } + return_trace (true); } @@ -1097,7 +1273,7 @@ struct Chain UnsizedArrayOf featureZ; /* Features. */ /*ChainSubtable firstSubtable;*//* Subtables. */ -/*subtableGlyphCoverageArray*/ /* Only if version >= 3. We don't use. */ +/*SubtableGlyphCoverage coverages*//* Only if version >= 3. */ public: DEFINE_SIZE_MIN (8 + 2 * sizeof (HBUINT)); @@ -1108,34 +1284,111 @@ struct Chain * The 'mort'/'morx' Table */ -template +template struct mortmorx { static constexpr hb_tag_t tableTag = TAG; bool has_data () const { return version != 0; } + struct accelerator_t + { + accelerator_t (hb_face_t *face) + { + hb_sanitize_context_t sc; + this->table = sc.reference_table (face); + + this->chain_count = table->get_chain_count (); + + this->accels = (hb_atomic_ptr_t *) hb_calloc (this->chain_count, sizeof (*accels)); + if (unlikely (!this->accels)) + { + this->chain_count = 0; + this->table.destroy (); + this->table = hb_blob_get_empty (); + } + } + ~accelerator_t () + { + for (unsigned int i = 0; i < this->chain_count; i++) + hb_free (this->accels[i]); + hb_free (this->accels); + this->table.destroy (); + } + + hb_blob_t *get_blob () const { return table.get_blob (); } + + template + hb_aat_layout_chain_accelerator_t *get_accel (unsigned chain_index, const Chain &chain, unsigned num_glyphs) const + { + if (unlikely (chain_index >= chain_count)) return nullptr; + + retry: + auto *accel = accels[chain_index].get_acquire (); + if (unlikely (!accel)) + { + accel = hb_aat_layout_chain_accelerator_t::create (chain, num_glyphs); + if (unlikely (!accel)) + return nullptr; + + if (unlikely (!accels[chain_index].cmpexch (nullptr, accel))) + { + hb_free (accel); + goto retry; + } + } + + return accel; + } + + hb_blob_ptr_t table; + unsigned int chain_count; + hb_atomic_ptr_t *accels; + }; + + void compile_flags (const hb_aat_map_builder_t *mapper, hb_aat_map_t *map) const { const Chain *chain = &firstChain; unsigned int count = chainCount; + if (unlikely (!map->chain_flags.resize (count))) + return; for (unsigned int i = 0; i < count; i++) { - map->chain_flags.push (chain->compile_flags (mapper)); + map->chain_flags[i].push (hb_aat_map_t::range_flags_t {chain->compile_flags (mapper), + mapper->range_first, + mapper->range_last}); chain = &StructAfter> (*chain); } } - void apply (hb_aat_apply_context_t *c) const + unsigned get_chain_count () const + { + return chainCount; + } + + void apply (hb_aat_apply_context_t *c, + const hb_aat_map_t &map, + const accelerator_t &accel) const { if (unlikely (!c->buffer->successful)) return; + + c->buffer->unsafe_to_concat (); + + if (c->buffer->len < HB_AAT_BUFFER_DIGEST_THRESHOLD) + c->buffer_digest = c->buffer->digest (); + else + c->buffer_digest = hb_set_digest_t::full (); + c->set_lookup_index (0); const Chain *chain = &firstChain; unsigned int count = chainCount; for (unsigned int i = 0; i < count; i++) { - chain->apply (c, c->plan->aat_map.chain_flags[i]); + auto *chain_accel = accel.get_accel (i, *chain, c->face->get_num_glyphs ()); + c->range_flags = &map.chain_flags[i]; + chain->apply (c, chain_accel); if (unlikely (!c->buffer->successful)) return; chain = &StructAfter> (*chain); } @@ -1144,7 +1397,10 @@ struct mortmorx bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (!version.sanitize (c) || !version || !chainCount.sanitize (c)) + if (!(version.sanitize (c) && + hb_barrier () && + version && + chainCount.sanitize (c))) return_trace (false); const Chain *chain = &firstChain; @@ -1153,6 +1409,7 @@ struct mortmorx { if (!chain->sanitize (c, version)) return_trace (false); + hb_barrier (); chain = &StructAfter> (*chain); } @@ -1171,8 +1428,15 @@ struct mortmorx DEFINE_SIZE_MIN (8); }; -struct morx : mortmorx {}; -struct mort : mortmorx {}; +struct morx : mortmorx {}; +struct mort : mortmorx {}; + +struct morx_accelerator_t : morx::accelerator_t { + morx_accelerator_t (hb_face_t *face) : morx::accelerator_t (face) {} +}; +struct mort_accelerator_t : mort::accelerator_t { + mort_accelerator_t (hb_face_t *face) : mort::accelerator_t (face) {} +}; } /* namespace AAT */ diff --git a/libs/harfbuzz/src/hb-aat-layout-opbd-table.hh b/libs/harfbuzz/src/hb-aat-layout-opbd-table.hh index 51b650fc3..dc75f5db5 100644 --- a/libs/harfbuzz/src/hb-aat-layout-opbd-table.hh +++ b/libs/harfbuzz/src/hb-aat-layout-opbd-table.hh @@ -133,8 +133,8 @@ struct opbd { switch (format) { - case 0: return u.format0.get_bounds (font, glyph_id, extents, this); - case 1: return u.format1.get_bounds (font, glyph_id, extents, this); + case 0: hb_barrier (); return u.format0.get_bounds (font, glyph_id, extents, this); + case 1: hb_barrier (); return u.format1.get_bounds (font, glyph_id, extents, this); default:return false; } } @@ -144,11 +144,12 @@ struct opbd TRACE_SANITIZE (this); if (unlikely (!c->check_struct (this) || version.major != 1)) return_trace (false); + hb_barrier (); switch (format) { - case 0: return_trace (u.format0.sanitize (c, this)); - case 1: return_trace (u.format1.sanitize (c, this)); + case 0: hb_barrier (); return_trace (u.format0.sanitize (c, this)); + case 1: hb_barrier (); return_trace (u.format1.sanitize (c, this)); default:return_trace (true); } } diff --git a/libs/harfbuzz/src/hb-aat-layout-trak-table.hh b/libs/harfbuzz/src/hb-aat-layout-trak-table.hh index 2ba9355b0..345a236e9 100644 --- a/libs/harfbuzz/src/hb-aat-layout-trak-table.hh +++ b/libs/harfbuzz/src/hb-aat-layout-trak-table.hh @@ -111,13 +111,13 @@ struct TrackData break; } } - if (!trackTableEntry) return 0.; + if (!trackTableEntry) return 0; /* * Choose size. */ unsigned int sizes = nSizes; - if (!sizes) return 0.; + if (!sizes) return 0; if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes); hb_array_t size_table ((base+sizeTable).arrayZ, sizes); @@ -134,6 +134,7 @@ struct TrackData { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && + hb_barrier () && sizeTable.sanitize (c, base, nSizes) && trackTable.sanitize (c, nTracks, base, nSizes))); } @@ -203,6 +204,7 @@ struct trak TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && + hb_barrier () && version.major == 1 && horizData.sanitize (c, this, this) && vertData.sanitize (c, this, this))); diff --git a/libs/harfbuzz/src/hb-aat-layout.cc b/libs/harfbuzz/src/hb-aat-layout.cc index d60126fe1..9da29e51c 100644 --- a/libs/harfbuzz/src/hb-aat-layout.cc +++ b/libs/harfbuzz/src/hb-aat-layout.cc @@ -55,7 +55,13 @@ AAT::hb_aat_apply_context_t::hb_aat_apply_context_t (const hb_ot_shape_plan_t *p buffer (buffer_), sanitizer (), ankr_table (&Null (AAT::ankr)), - gdef_table (face->table.GDEF->table), + gdef_table ( +#ifndef HB_NO_OT_LAYOUT + face->table.GDEF->table +#else + &Null (GDEF) +#endif + ), lookup_index (0) { sanitizer.init (blob); @@ -205,14 +211,14 @@ void hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper, hb_aat_map_t *map) { - const AAT::morx& morx = *mapper->face->table.morx; + const AAT::morx& morx = *mapper->face->table.morx->table; if (morx.has_data ()) { morx.compile_flags (mapper, map); return; } - const AAT::mort& mort = *mapper->face->table.mort; + const AAT::mort& mort = *mapper->face->table.mort->table; if (mort.has_data ()) { mort.compile_flags (mapper, map); @@ -237,35 +243,47 @@ hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper, hb_bool_t hb_aat_layout_has_substitution (hb_face_t *face) { - return face->table.morx->has_data () || - face->table.mort->has_data (); + return face->table.morx->table->has_data () || + face->table.mort->table->has_data (); } void hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, - hb_buffer_t *buffer) + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned num_features) { - hb_blob_t *morx_blob = font->face->table.morx.get_blob (); - const AAT::morx& morx = *morx_blob->as (); - if (morx.has_data ()) + 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; + builder.compile (map); + { - AAT::hb_aat_apply_context_t c (plan, font, buffer, morx_blob); - if (!buffer->message (font, "start table morx")) return; - morx.apply (&c); - (void) buffer->message (font, "end table morx"); - return; + auto &accel = *font->face->table.morx; + const AAT::morx& morx = *accel.table; + if (morx.has_data ()) + { + AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ()); + if (!buffer->message (font, "start table morx")) return; + morx.apply (&c, map, accel); + (void) buffer->message (font, "end table morx"); + return; + } } - hb_blob_t *mort_blob = font->face->table.mort.get_blob (); - const AAT::mort& mort = *mort_blob->as (); - if (mort.has_data ()) { - AAT::hb_aat_apply_context_t c (plan, font, buffer, mort_blob); - if (!buffer->message (font, "start table mort")) return; - mort.apply (&c); - (void) buffer->message (font, "end table mort"); - return; + auto &accel = *font->face->table.mort; + const AAT::mort& mort = *accel.table; + if (mort.has_data ()) + { + AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ()); + if (!buffer->message (font, "start table mort")) return; + mort.apply (&c, map, accel); + (void) buffer->message (font, "end table mort"); + return; + } } } @@ -289,7 +307,7 @@ is_deleted_glyph (const hb_glyph_info_t *info) void hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer) { - hb_ot_layout_delete_glyphs_inplace (buffer, is_deleted_glyph); + buffer->delete_glyphs_inplace (is_deleted_glyph); } /** @@ -308,7 +326,7 @@ hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer) hb_bool_t hb_aat_layout_has_positioning (hb_face_t *face) { - return face->table.kerx->has_data (); + return face->table.kerx->table->has_data (); } void @@ -316,13 +334,12 @@ hb_aat_layout_position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) { - hb_blob_t *kerx_blob = font->face->table.kerx.get_blob (); - const AAT::kerx& kerx = *kerx_blob->as (); + auto &accel = *font->face->table.kerx; - AAT::hb_aat_apply_context_t c (plan, font, buffer, kerx_blob); + AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ()); if (!buffer->message (font, "start table kerx")) return; c.set_ankr_table (font->face->table.ankr.get ()); - kerx.apply (&c); + accel.apply (&c); (void) buffer->message (font, "end table kerx"); } diff --git a/libs/harfbuzz/src/hb-aat-layout.h b/libs/harfbuzz/src/hb-aat-layout.h index 9af274008..c682a2f6d 100644 --- a/libs/harfbuzz/src/hb-aat-layout.h +++ b/libs/harfbuzz/src/hb-aat-layout.h @@ -40,7 +40,7 @@ HB_BEGIN_DECLS * @HB_AAT_LAYOUT_FEATURE_TYPE_INVALID: Initial, unset feature type * @HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC: [All Typographic Features](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type0) * @HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES: [Ligatures](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type1) - * @HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION: [Cursive Connection](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type2) + * @HB_AAT_LAYOUT_FEATURE_TYPE_CURSIVE_CONNECTION: [Cursive Connection](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type2) * @HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE: [Letter Case](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type3) * @HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION: [Vertical Substitution](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type4) * @HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT: [Linguistic Rearrangement](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type5) @@ -88,7 +88,7 @@ typedef enum HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC = 0, HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES = 1, - HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION = 2, + HB_AAT_LAYOUT_FEATURE_TYPE_CURSIVE_CONNECTION = 2, HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE = 3, HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION = 4, HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT = 5, diff --git a/libs/harfbuzz/src/hb-aat-layout.hh b/libs/harfbuzz/src/hb-aat-layout.hh index 5e4e3bda1..15c382aa9 100644 --- a/libs/harfbuzz/src/hb-aat-layout.hh +++ b/libs/harfbuzz/src/hb-aat-layout.hh @@ -53,7 +53,9 @@ hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper, HB_INTERNAL void hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, - hb_buffer_t *buffer); + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned num_features); HB_INTERNAL void hb_aat_layout_zero_width_deleted_glyphs (hb_buffer_t *buffer); diff --git a/libs/harfbuzz/src/hb-aat-ltag-table.hh b/libs/harfbuzz/src/hb-aat-ltag-table.hh index 6d771e151..c974025d4 100644 --- a/libs/harfbuzz/src/hb-aat-ltag-table.hh +++ b/libs/harfbuzz/src/hb-aat-ltag-table.hh @@ -46,7 +46,9 @@ struct FTStringRange bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && (base+tag).sanitize (c, length)); + return_trace (c->check_struct (this) && + hb_barrier () && + (base+tag).sanitize (c, length)); } protected: @@ -73,6 +75,7 @@ struct ltag { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && + hb_barrier () && version >= 1 && tagRanges.sanitize (c, this))); } diff --git a/libs/harfbuzz/src/hb-aat-map.cc b/libs/harfbuzz/src/hb-aat-map.cc index 2c38c3502..5bdb8004f 100644 --- a/libs/harfbuzz/src/hb-aat-map.cc +++ b/libs/harfbuzz/src/hb-aat-map.cc @@ -36,27 +36,29 @@ #include "hb-aat-layout-feat-table.hh" -void hb_aat_map_builder_t::add_feature (hb_tag_t tag, unsigned value) +void hb_aat_map_builder_t::add_feature (const hb_feature_t &feature) { if (!face->table.feat->has_data ()) return; - if (tag == HB_TAG ('a','a','l','t')) + if (feature.tag == HB_TAG ('a','a','l','t')) { if (!face->table.feat->exposes_feature (HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES)) return; - feature_info_t *info = features.push(); - info->type = HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES; - info->setting = (hb_aat_layout_feature_selector_t) value; - info->seq = features.length; - info->is_exclusive = true; + feature_range_t *range = features.push(); + range->start = feature.start; + range->end = feature.end; + range->info.type = HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES; + range->info.setting = (hb_aat_layout_feature_selector_t) feature.value; + range->info.seq = features.length; + range->info.is_exclusive = true; return; } - const hb_aat_feature_mapping_t *mapping = hb_aat_layout_find_feature_mapping (tag); + const hb_aat_feature_mapping_t *mapping = hb_aat_layout_find_feature_mapping (feature.tag); if (!mapping) return; - const AAT::FeatureName* feature = &face->table.feat->get_feature (mapping->aatFeatureType); - if (!feature->has_data ()) + const AAT::FeatureName* feature_name = &face->table.feat->get_feature (mapping->aatFeatureType); + if (!feature_name->has_data ()) { /* Special case: Chain::compile_flags will fall back to the deprecated version of * small-caps if necessary, so we need to check for that possibility. @@ -64,38 +66,106 @@ void hb_aat_map_builder_t::add_feature (hb_tag_t tag, unsigned value) if (mapping->aatFeatureType == HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE && mapping->selectorToEnable == HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS) { - feature = &face->table.feat->get_feature (HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE); - if (!feature->has_data ()) return; + feature_name = &face->table.feat->get_feature (HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE); + if (!feature_name->has_data ()) return; } else return; } - feature_info_t *info = features.push(); - info->type = mapping->aatFeatureType; - info->setting = value ? mapping->selectorToEnable : mapping->selectorToDisable; - info->seq = features.length; - info->is_exclusive = feature->is_exclusive (); + feature_range_t *range = features.push(); + range->start = feature.start; + range->end = feature.end; + range->info.type = mapping->aatFeatureType; + range->info.setting = feature.value ? mapping->selectorToEnable : mapping->selectorToDisable; + range->info.seq = features.length; + range->info.is_exclusive = feature_name->is_exclusive (); } void hb_aat_map_builder_t::compile (hb_aat_map_t &m) { - /* Sort features and merge duplicates */ - if (features.length) + /* Compute active features per range, and compile each. */ + + /* Sort features by start/end events. */ + hb_vector_t feature_events; + for (unsigned int i = 0; i < features.length; i++) + { + auto &feature = features[i]; + + if (features[i].start == features[i].end) + continue; + + feature_event_t *event; + + event = feature_events.push (); + event->index = features[i].start; + event->start = true; + event->feature = feature.info; + + event = feature_events.push (); + event->index = features[i].end; + event->start = false; + event->feature = feature.info; + } + feature_events.qsort (); + /* Add a strategic final event. */ + { + feature_info_t feature; + feature.seq = features.length + 1; + + feature_event_t *event = feature_events.push (); + event->index = -1; /* This value does magic. */ + event->start = false; + event->feature = feature; + } + + /* Scan events and save features for each range. */ + hb_sorted_vector_t active_features; + unsigned int last_index = 0; + for (unsigned int i = 0; i < feature_events.length; i++) { - features.qsort (); - unsigned int j = 0; - for (unsigned int i = 1; i < features.length; i++) - if (features[i].type != features[j].type || - /* Nonexclusive feature selectors come in even/odd pairs to turn a setting on/off - * respectively, so we mask out the low-order bit when checking for "duplicates" - * (selectors referring to the same feature setting) here. */ - (!features[i].is_exclusive && ((features[i].setting & ~1) != (features[j].setting & ~1)))) - features[++j] = features[i]; - features.shrink (j + 1); + feature_event_t *event = &feature_events[i]; + + if (event->index != last_index) + { + /* Save a snapshot of active features and the range. */ + + /* Sort features and merge duplicates */ + current_features = active_features; + range_first = last_index; + range_last = event->index - 1; + if (current_features.length) + { + current_features.qsort (); + unsigned int j = 0; + for (unsigned int i = 1; i < current_features.length; i++) + if (current_features[i].type != current_features[j].type || + /* Nonexclusive feature selectors come in even/odd pairs to turn a setting on/off + * respectively, so we mask out the low-order bit when checking for "duplicates" + * (selectors referring to the same feature setting) here. */ + (!current_features[i].is_exclusive && ((current_features[i].setting & ~1) != (current_features[j].setting & ~1)))) + current_features[++j] = current_features[i]; + current_features.shrink (j + 1); + } + + hb_aat_layout_compile_map (this, &m); + + last_index = event->index; + } + + if (event->start) + { + active_features.push (event->feature); + } else { + feature_info_t *feature = active_features.lsearch (event->feature); + if (feature) + active_features.remove_ordered (feature - active_features.arrayZ); + } } - hb_aat_layout_compile_map (this, &m); + for (auto &chain_flags : m.chain_flags) + // With our above setup this value is one less than desired; adjust it. + chain_flags.tail().cluster_last = HB_FEATURE_GLOBAL_END; } diff --git a/libs/harfbuzz/src/hb-aat-map.hh b/libs/harfbuzz/src/hb-aat-map.hh index c914f58d7..cb22ffee4 100644 --- a/libs/harfbuzz/src/hb-aat-map.hh +++ b/libs/harfbuzz/src/hb-aat-map.hh @@ -35,16 +35,15 @@ struct hb_aat_map_t friend struct hb_aat_map_builder_t; public: - - void init () + struct range_flags_t { - memset (this, 0, sizeof (*this)); - chain_flags.init (); - } - void fini () { chain_flags.fini (); } + hb_mask_t flags; + unsigned cluster_first; + unsigned cluster_last; // end - 1 + }; public: - hb_vector_t chain_flags; + hb_vector_t> chain_flags; }; struct hb_aat_map_builder_t @@ -56,7 +55,7 @@ struct hb_aat_map_builder_t face (face_), props (props_) {} - HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value=1); + HB_INTERNAL void add_feature (const hb_feature_t &feature); HB_INTERNAL void compile (hb_aat_map_t &m); @@ -78,7 +77,7 @@ struct hb_aat_map_builder_t return (a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0); } - /* compares type & setting only, not is_exclusive flag or seq number */ + /* compares type & setting only */ int cmp (const feature_info_t& f) const { return (f.type != type) ? (f.type < type ? -1 : 1) : @@ -86,12 +85,38 @@ struct hb_aat_map_builder_t } }; + struct feature_range_t + { + feature_info_t info; + unsigned start; + unsigned end; + }; + + private: + struct feature_event_t + { + unsigned int index; + bool start; + feature_info_t feature; + + HB_INTERNAL static int cmp (const void *pa, const void *pb) { + const feature_event_t *a = (const feature_event_t *) pa; + const feature_event_t *b = (const feature_event_t *) pb; + return a->index < b->index ? -1 : a->index > b->index ? 1 : + a->start < b->start ? -1 : a->start > b->start ? 1 : + feature_info_t::cmp (&a->feature, &b->feature); + } + }; + public: hb_face_t *face; hb_segment_properties_t props; public: - hb_sorted_vector_t features; + hb_sorted_vector_t features; + hb_sorted_vector_t current_features; + unsigned range_first = HB_FEATURE_GLOBAL_START; + unsigned range_last = HB_FEATURE_GLOBAL_END; }; diff --git a/libs/harfbuzz/src/hb-algs.hh b/libs/harfbuzz/src/hb-algs.hh index cc37c073d..b02793a09 100644 --- a/libs/harfbuzz/src/hb-algs.hh +++ b/libs/harfbuzz/src/hb-algs.hh @@ -87,6 +87,19 @@ static inline constexpr uint16_t hb_uint16_swap (uint16_t v) static inline constexpr uint32_t hb_uint32_swap (uint32_t v) { return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); } +#ifndef HB_FAST_INT_ACCESS +#if defined(__OPTIMIZE__) && \ + defined(__BYTE_ORDER) && \ + (__BYTE_ORDER == __BIG_ENDIAN || \ + (__BYTE_ORDER == __LITTLE_ENDIAN && \ + hb_has_builtin(__builtin_bswap16) && \ + hb_has_builtin(__builtin_bswap32))) +#define HB_FAST_INT_ACCESS 1 +#else +#define HB_FAST_INT_ACCESS 0 +#endif +#endif + template struct BEInt; template @@ -101,20 +114,25 @@ struct BEInt template struct BEInt { + struct __attribute__((packed)) packed_uint16_t { uint16_t v; }; + public: BEInt () = default; - constexpr BEInt (Type V) : v {uint8_t ((V >> 8) & 0xFF), - uint8_t ((V ) & 0xFF)} {} - struct __attribute__((packed)) packed_uint16_t { uint16_t v; }; - constexpr operator Type () const - { -#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \ - ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \ - defined(__BYTE_ORDER) && \ - (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN) - /* Spoon-feed the compiler a big-endian integer with alignment 1. - * https://github.com/harfbuzz/harfbuzz/pull/1398 */ + BEInt (Type V) +#if HB_FAST_INT_ACCESS +#if __BYTE_ORDER == __LITTLE_ENDIAN + { ((packed_uint16_t *) v)->v = __builtin_bswap16 (V); } +#else /* __BYTE_ORDER == __BIG_ENDIAN */ + { ((packed_uint16_t *) v)->v = V; } +#endif +#else + : v {uint8_t ((V >> 8) & 0xFF), + uint8_t ((V ) & 0xFF)} {} +#endif + + constexpr operator Type () const { +#if HB_FAST_INT_ACCESS #if __BYTE_ORDER == __LITTLE_ENDIAN return __builtin_bswap16 (((packed_uint16_t *) v)->v); #else /* __BYTE_ORDER == __BIG_ENDIAN */ @@ -145,21 +163,27 @@ struct BEInt template struct BEInt { + struct __attribute__((packed)) packed_uint32_t { uint32_t v; }; + public: BEInt () = default; - constexpr BEInt (Type V) : v {uint8_t ((V >> 24) & 0xFF), - uint8_t ((V >> 16) & 0xFF), - uint8_t ((V >> 8) & 0xFF), - uint8_t ((V ) & 0xFF)} {} - struct __attribute__((packed)) packed_uint32_t { uint32_t v; }; + BEInt (Type V) +#if HB_FAST_INT_ACCESS +#if __BYTE_ORDER == __LITTLE_ENDIAN + { ((packed_uint32_t *) v)->v = __builtin_bswap32 (V); } +#else /* __BYTE_ORDER == __BIG_ENDIAN */ + { ((packed_uint32_t *) v)->v = V; } +#endif +#else + : v {uint8_t ((V >> 24) & 0xFF), + uint8_t ((V >> 16) & 0xFF), + uint8_t ((V >> 8) & 0xFF), + uint8_t ((V ) & 0xFF)} {} +#endif + constexpr operator Type () const { -#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \ - ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \ - defined(__BYTE_ORDER) && \ - (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN) - /* Spoon-feed the compiler a big-endian integer with alignment 1. - * https://github.com/harfbuzz/harfbuzz/pull/1398 */ +#if HB_FAST_INT_ACCESS #if __BYTE_ORDER == __LITTLE_ENDIAN return __builtin_bswap32 (((packed_uint32_t *) v)->v); #else /* __BYTE_ORDER == __BIG_ENDIAN */ @@ -178,8 +202,12 @@ struct BEInt /* Floats. */ /* We want our rounding towards +infinity. */ +static inline double +_hb_roundf (double x) { return floor (x + .5); } + static inline float _hb_roundf (float x) { return floorf (x + .5f); } + #define roundf(x) _hb_roundf(x) @@ -229,23 +257,123 @@ struct } HB_FUNCOBJ (hb_bool); + +/* The MIT License + + Copyright (C) 2012 Zilong Tan (eric.zltan@gmail.com) + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + + +// Compression function for Merkle-Damgard construction. +// This function is generated using the framework provided. +#define mix(h) ( \ + (void) ((h) ^= (h) >> 23), \ + (void) ((h) *= 0x2127599bf4325c37ULL), \ + (h) ^= (h) >> 47) + +static inline uint64_t fasthash64(const void *buf, size_t len, uint64_t seed) +{ + struct __attribute__((packed)) packed_uint64_t { uint64_t v; }; + const uint64_t m = 0x880355f21e6d1965ULL; + const packed_uint64_t *pos = (const packed_uint64_t *)buf; + const packed_uint64_t *end = pos + (len / 8); + const unsigned char *pos2; + uint64_t h = seed ^ (len * m); + uint64_t v; + +#ifndef HB_OPTIMIZE_SIZE + if (((uintptr_t) pos & 7) == 0) + { + while (pos != end) + { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-align" + v = * (const uint64_t *) (pos++); +#pragma GCC diagnostic pop + h ^= mix(v); + h *= m; + } + } + else +#endif + { + while (pos != end) + { + v = pos++->v; + h ^= mix(v); + h *= m; + } + } + + pos2 = (const unsigned char*)pos; + v = 0; + + switch (len & 7) { + case 7: v ^= (uint64_t)pos2[6] << 48; HB_FALLTHROUGH; + case 6: v ^= (uint64_t)pos2[5] << 40; HB_FALLTHROUGH; + case 5: v ^= (uint64_t)pos2[4] << 32; HB_FALLTHROUGH; + case 4: v ^= (uint64_t)pos2[3] << 24; HB_FALLTHROUGH; + case 3: v ^= (uint64_t)pos2[2] << 16; HB_FALLTHROUGH; + case 2: v ^= (uint64_t)pos2[1] << 8; HB_FALLTHROUGH; + case 1: v ^= (uint64_t)pos2[0]; + h ^= mix(v); + h *= m; + } + + return mix(h); +} + +static inline uint32_t fasthash32(const void *buf, size_t len, uint32_t seed) +{ + // the following trick converts the 64-bit hashcode to Fermat + // residue, which shall retain information from both the higher + // and lower parts of hashcode. + uint64_t h = fasthash64(buf, len, seed); + return h - (h >> 32); +} + struct { private: template constexpr auto - impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, hb_deref (v).hash ()) - - template constexpr uint32_t - impl (const hb::shared_ptr& v, hb_priority<1>) const - { - return v.get () ? v.get ()->hash () : 0; - } - template constexpr uint32_t - impl (const hb::unique_ptr& v, hb_priority<1>) const - { - return v.get () ? v.get ()->hash () : 0; - } + impl (const T& v, hb_priority<2>) const HB_RETURN (uint32_t, hb_deref (v).hash ()) + + // Horrible: std:hash() of integers seems to be identity in gcc / clang?! + // https://github.com/harfbuzz/harfbuzz/pull/4228 + // + // For performance characteristics see: + // https://github.com/harfbuzz/harfbuzz/pull/4228#issuecomment-1565079537 + template ::value && sizeof (T) <= sizeof (uint32_t))> constexpr auto + impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, (uint32_t) v * 2654435761u /* Knuh's multiplicative hash */) + template ::value && sizeof (T) > sizeof (uint32_t))> constexpr auto + impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, (uint32_t) (v ^ (v >> 32)) * 2654435761u /* Knuth's multiplicative hash */) + + template ::value)> constexpr auto + impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, fasthash32 (std::addressof (v), sizeof (T), 0xf437ffe6)) template constexpr auto impl (const T& v, hb_priority<0>) const HB_RETURN (uint32_t, std::hash>{} (hb_deref (v))) @@ -495,6 +623,17 @@ struct } HB_FUNCOBJ (hb_equal); +struct +{ + template void + operator () (T& a, T& b) const + { + using std::swap; // allow ADL + swap (a, b); + } +} +HB_FUNCOBJ (hb_swap); + template struct hb_pair_t @@ -507,7 +646,7 @@ struct hb_pair_t hb_enable_if (std::is_default_constructible::value && std::is_default_constructible::value)> hb_pair_t () : first (), second () {} - hb_pair_t (T1 a, T2 b) : first (a), second (b) {} + hb_pair_t (T1 a, T2 b) : first (std::forward (a)), second (std::forward (b)) {} template (const pair_t& o) const { return first > o.first || (first == o.first && second > o.second); } bool operator <= (const pair_t& o) const { return !(*this > o); } + static int cmp (const void *pa, const void *pb) + { + pair_t *a = (pair_t *) pa; + pair_t *b = (pair_t *) pb; + + if (a->first < b->first) return -1; + if (a->first > b->first) return +1; + if (a->second < b->second) return -1; + if (a->second > b->second) return +1; + return 0; + } + + friend void swap (hb_pair_t& a, hb_pair_t& b) noexcept + { + hb_swap (a.first, b.first); + hb_swap (a.second, b.second); + } + + T1 first; T2 second; }; template static inline hb_pair_t hb_pair (T1&& a, T2&& b) { return hb_pair_t (a, b); } +typedef hb_pair_t hb_codepoint_pair_t; + struct { template constexpr typename Pair::first_t @@ -570,17 +730,6 @@ struct } HB_FUNCOBJ (hb_clamp); -struct -{ - template void - operator () (T& a, T& b) const - { - using std::swap; // allow ADL - swap (a, b); - } -} -HB_FUNCOBJ (hb_swap); - /* * Bithacks. */ @@ -590,13 +739,17 @@ template static inline unsigned int hb_popcount (T v) { -#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) +#if hb_has_builtin(__builtin_popcount) if (sizeof (T) <= sizeof (unsigned int)) return __builtin_popcount (v); +#endif +#if hb_has_builtin(__builtin_popcountl) if (sizeof (T) <= sizeof (unsigned long)) return __builtin_popcountl (v); +#endif +#if hb_has_builtin(__builtin_popcountll) if (sizeof (T) <= sizeof (unsigned long long)) return __builtin_popcountll (v); #endif @@ -612,8 +765,10 @@ hb_popcount (T v) if (sizeof (T) == 8) { - unsigned int shift = 32; - return hb_popcount ((uint32_t) v) + hb_popcount ((uint32_t) (v >> shift)); + uint64_t y = (uint64_t) v; + y -= ((y >> 1) & 0x5555555555555555ull); + y = (y & 0x3333333333333333ull) + (y >> 2 & 0x3333333333333333ull); + return ((y + (y >> 4)) & 0xf0f0f0f0f0f0f0full) * 0x101010101010101ull >> 56; } if (sizeof (T) == 16) @@ -633,13 +788,17 @@ hb_bit_storage (T v) { if (unlikely (!v)) return 0; -#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) +#if hb_has_builtin(__builtin_clz) if (sizeof (T) <= sizeof (unsigned int)) return sizeof (unsigned int) * 8 - __builtin_clz (v); +#endif +#if hb_has_builtin(__builtin_clzl) if (sizeof (T) <= sizeof (unsigned long)) return sizeof (unsigned long) * 8 - __builtin_clzl (v); +#endif +#if hb_has_builtin(__builtin_clzll) if (sizeof (T) <= sizeof (unsigned long long)) return sizeof (unsigned long long) * 8 - __builtin_clzll (v); #endif @@ -707,13 +866,17 @@ hb_ctz (T v) { if (unlikely (!v)) return 8 * sizeof (T); -#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) +#if hb_has_builtin(__builtin_ctz) if (sizeof (T) <= sizeof (unsigned int)) return __builtin_ctz (v); +#endif +#if hb_has_builtin(__builtin_ctzl) if (sizeof (T) <= sizeof (unsigned long)) return __builtin_ctzl (v); +#endif +#if hb_has_builtin(__builtin_ctzll) if (sizeof (T) <= sizeof (unsigned long long)) return __builtin_ctzll (v); #endif @@ -829,7 +992,7 @@ static inline void * hb_memset (void *s, int c, unsigned int n) { /* It's illegal to pass NULL to memset(), even if n is zero. */ - if (unlikely (!n)) return 0; + if (unlikely (!n)) return s; return memset (s, c, n); } @@ -849,19 +1012,14 @@ hb_in_range (T u, T lo, T hi) return (T)(u - lo) <= (T)(hi - lo); } template static inline bool -hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2) -{ - return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2); -} -template static inline bool -hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3) +hb_in_ranges (T u, T lo1, T hi1) { - return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3); + return hb_in_range (u, lo1, hi1); } -template static inline bool -hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3, T lo4, T hi4) +template static inline bool +hb_in_ranges (T u, T lo1, T hi1, Ts... ds) { - return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3) || hb_in_range (u, lo4, hi4); + return hb_in_range (u, lo1, hi1) || hb_in_ranges (u, ds...); } @@ -869,10 +1027,18 @@ hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3, T lo4, T hi4) * Overflow checking. */ -/* Consider __builtin_mul_overflow use here also */ static inline bool -hb_unsigned_mul_overflows (unsigned int count, unsigned int size) +hb_unsigned_mul_overflows (unsigned int count, unsigned int size, unsigned *result = nullptr) { +#if hb_has_builtin(__builtin_mul_overflow) + unsigned stack_result; + if (!result) + result = &stack_result; + return __builtin_mul_overflow (count, size, result); +#endif + + if (result) + *result = count * size; return (size > 0) && (count >= ((unsigned int) -1) / size); } @@ -891,6 +1057,18 @@ _hb_cmp_method (const void *pkey, const void *pval, Ts... ds) return val.cmp (key, ds...); } +template +static int +_hb_cmp_operator (const void *pkey, const void *pval) +{ + const K& key = * (const K*) pkey; + const V& val = * (const V*) pval; + + if (key < val) return -1; + if (key > val) return 1; + return 0; +} + template static inline bool hb_bsearch_impl (unsigned *pos, /* Out */ @@ -1164,9 +1342,12 @@ hb_qsort (void *base, size_t nel, size_t width, } -template static inline void -hb_stable_sort (T *array, unsigned int len, int(*compar)(const T2 *, const T2 *), T3 *array2) +template static inline void +hb_stable_sort (T *array, unsigned int len, int(*compar)(const T2 *, const T2 *), T3 *array2 = nullptr) { + static_assert (hb_is_trivially_copy_assignable (T), ""); + static_assert (hb_is_trivially_copy_assignable (T3), ""); + for (unsigned int i = 1; i < len; i++) { unsigned int j = i; @@ -1189,12 +1370,6 @@ hb_stable_sort (T *array, unsigned int len, int(*compar)(const T2 *, const T2 *) } } -template static inline void -hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *)) -{ - hb_stable_sort (array, len, compar, (int *) nullptr); -} - static inline hb_bool_t hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out) { @@ -1322,47 +1497,62 @@ struct HB_FUNCOBJ (hb_dec); -/* Compiler-assisted vectorization. */ - -/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))), - * basically a fixed-size bitset. */ -template -struct hb_vector_size_t +/* Adapted from kurbo implementation with extra parameters added, + * and finding for a particular range instead of 0. + * + * For documentation and implementation see: + * + * [ITP method]: https://en.wikipedia.org/wiki/ITP_Method + * [An Enhancement of the Bisection Method Average Performance Preserving Minmax Optimality]: https://dl.acm.org/doi/10.1145/3423597 + * https://docs.rs/kurbo/0.8.1/kurbo/common/fn.solve_itp.html + * https://github.com/linebender/kurbo/blob/fd839c25ea0c98576c7ce5789305822675a89938/src/common.rs#L162-L248 + */ +template +double solve_itp (func_t f, + double a, double b, + double epsilon, + double min_y, double max_y, + double &ya, double &yb, double &y) { - elt_t& operator [] (unsigned int i) { return v[i]; } - const elt_t& operator [] (unsigned int i) const { return v[i]; } - - void clear (unsigned char v = 0) { memset (this, v, sizeof (*this)); } - - template - hb_vector_size_t process (const Op& op) const - { - hb_vector_size_t r; - for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++) - r.v[i] = op (v[i]); - return r; - } - template - hb_vector_size_t process (const Op& op, const hb_vector_size_t &o) const + unsigned n1_2 = (unsigned) (hb_max (ceil (log2 ((b - a) / epsilon)) - 1.0, 0.0)); + const unsigned n0 = 1; // Hardwired + const double k1 = 0.2 / (b - a); // Hardwired. + unsigned nmax = n0 + n1_2; + double scaled_epsilon = epsilon * double (1llu << nmax); + double _2_epsilon = 2.0 * epsilon; + while (b - a > _2_epsilon) { - hb_vector_size_t r; - for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++) - r.v[i] = op (v[i], o.v[i]); - return r; + double x1_2 = 0.5 * (a + b); + double r = scaled_epsilon - 0.5 * (b - a); + double xf = (yb * a - ya * b) / (yb - ya); + double sigma = x1_2 - xf; + double b_a = b - a; + // This has k2 = 2 hardwired for efficiency. + double b_a_k2 = b_a * b_a; + double delta = k1 * b_a_k2; + int sigma_sign = sigma >= 0 ? +1 : -1; + double xt = delta <= fabs (x1_2 - xf) ? xf + delta * sigma_sign : x1_2; + double xitp = fabs (xt - x1_2) <= r ? xt : x1_2 - r * sigma_sign; + double yitp = f (xitp); + if (yitp > max_y) + { + b = xitp; + yb = yitp; + } + else if (yitp < min_y) + { + a = xitp; + ya = yitp; + } + else + { + y = yitp; + return xitp; + } + scaled_epsilon *= 0.5; } - hb_vector_size_t operator | (const hb_vector_size_t &o) const - { return process (hb_bitwise_or, o); } - hb_vector_size_t operator & (const hb_vector_size_t &o) const - { return process (hb_bitwise_and, o); } - hb_vector_size_t operator ^ (const hb_vector_size_t &o) const - { return process (hb_bitwise_xor, o); } - hb_vector_size_t operator ~ () const - { return process (hb_bitwise_neg); } - - private: - static_assert (0 == byte_size % sizeof (elt_t), ""); - elt_t v[byte_size / sizeof (elt_t)]; -}; + return 0.5 * (a + b); +} #endif /* HB_ALGS_HH */ diff --git a/libs/harfbuzz/src/hb-array.hh b/libs/harfbuzz/src/hb-array.hh index 5884007c1..9037179bc 100644 --- a/libs/harfbuzz/src/hb-array.hh +++ b/libs/harfbuzz/src/hb-array.hh @@ -47,6 +47,8 @@ enum hb_not_found_t template struct hb_array_t : hb_iter_with_fallback_t, Type&> { + static constexpr bool realloc_move = true; + /* * Constructors. */ @@ -75,11 +77,25 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> */ typedef Type& __item_t__; static constexpr bool is_random_access_iterator = true; + static constexpr bool has_fast_len = true; + Type& __item__ () const + { + if (unlikely (!length)) return CrapOrNull (Type); + return *arrayZ; + } Type& __item_at__ (unsigned i) const { if (unlikely (i >= length)) return CrapOrNull (Type); return arrayZ[i]; } + void __next__ () + { + if (unlikely (!length)) + return; + length--; + backwards_length++; + arrayZ++; + } void __forward__ (unsigned n) { if (unlikely (n > length)) @@ -88,6 +104,14 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> backwards_length += n; arrayZ += n; } + void __prev__ () + { + if (unlikely (!backwards_length)) + return; + length++; + backwards_length--; + arrayZ--; + } void __rewind__ (unsigned n) { if (unlikely (n > backwards_length)) @@ -100,10 +124,18 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> /* Ouch. The operator== compares the contents of the array. For range-based for loops, * it's best if we can just compare arrayZ, though comparing contents is still fast, * but also would require that Type has operator==. As such, we optimize this operator - * for range-based for loop and just compare arrayZ and length. */ + * for range-based for loop and just compare arrayZ and length. + * + * The above comment is outdated now because we implemented separate begin/end to + * objects that were using hb_array_t for range-based loop before. */ bool operator != (const hb_array_t& o) const { return this->arrayZ != o.arrayZ || this->length != o.length; } + /* Faster range-based for loop without bounds-check. */ + Type *begin () const { return arrayZ; } + Type *end () const { return arrayZ + length; } + + /* Extra operators. */ Type * operator & () const { return arrayZ; } @@ -112,10 +144,15 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> HB_INTERNAL bool operator == (const hb_array_t &o) const; - uint32_t hash () const { - uint32_t current = 0; - for (unsigned int i = 0; i < this->length; i++) { - current = current * 31 + hb_hash (this->arrayZ[i]); + uint32_t hash () const + { + // FNV-1a hash function + // https://github.com/harfbuzz/harfbuzz/pull/4228 + uint32_t current = /*cbf29ce4*/0x84222325; + for (auto &v : *this) + { + current = current ^ hb_hash (v); + current = current * 16777619; } return current; } @@ -184,23 +221,18 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> hb_sorted_array_t qsort (int (*cmp_)(const void*, const void*)) { + //static_assert (hb_enable_if (hb_is_trivially_copy_assignable(Type)), ""); if (likely (length)) hb_qsort (arrayZ, length, this->get_item_size (), cmp_); return hb_sorted_array_t (*this); } hb_sorted_array_t qsort () { + //static_assert (hb_enable_if (hb_is_trivially_copy_assignable(Type)), ""); if (likely (length)) hb_qsort (arrayZ, length, this->get_item_size (), Type::cmp); return hb_sorted_array_t (*this); } - void qsort (unsigned int start, unsigned int end) - { - end = hb_min (end, length); - assert (start <= end); - if (likely (start < end)) - hb_qsort (arrayZ + start, end - start, this->get_item_size (), Type::cmp); - } /* * Other methods. @@ -262,17 +294,31 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> void fini () { hb_free ((void *) arrayZ); arrayZ = nullptr; length = 0; } - template + template )))> hb_array_t copy (hb_serialize_context_t *c) const { TRACE_SERIALIZE (this); auto* out = c->start_embed (arrayZ); - if (unlikely (!c->extend_size (out, get_size ()))) return_trace (hb_array_t ()); + if (unlikely (!c->extend_size (out, get_size (), false))) return_trace (hb_array_t ()); for (unsigned i = 0; i < length; i++) out[i] = arrayZ[i]; /* TODO: add version that calls c->copy() */ return_trace (hb_array_t (out, length)); } + template ))> + hb_array_t copy (hb_serialize_context_t *c) const + { + TRACE_SERIALIZE (this); + auto* out = c->start_embed (arrayZ); + if (unlikely (!c->extend_size (out, get_size (), false))) return_trace (hb_array_t ()); + hb_memcpy (out, arrayZ, get_size ()); + return_trace (hb_array_t (out, length)); + } + template bool sanitize (hb_sanitize_context_t *c) const { return c->check_array (arrayZ, length); } @@ -287,6 +333,9 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> unsigned int backwards_length = 0; }; template inline hb_array_t +hb_array () +{ return hb_array_t (); } +template inline hb_array_t hb_array (T *array, unsigned int length) { return hb_array_t (array, length); } template inline hb_array_t @@ -295,13 +344,14 @@ hb_array (T (&array_)[length_]) template struct hb_sorted_array_t : - hb_iter_t, Type&>, - hb_array_t + hb_array_t, + hb_iter_t, Type&> { typedef hb_iter_t iter_base_t; HB_ITER_USING (iter_base_t); static constexpr bool is_random_access_iterator = true; static constexpr bool is_sorted_iterator = true; + static constexpr bool has_fast_len = true; hb_sorted_array_t () = default; hb_sorted_array_t (const hb_sorted_array_t&) = default; @@ -316,8 +366,8 @@ struct hb_sorted_array_t : template constexpr hb_sorted_array_t (const hb_array_t &o) : - hb_iter_t (), - hb_array_t (o) {} + hb_array_t (o), + hb_iter_t () {} template hb_sorted_array_t& operator = (const hb_array_t &o) @@ -329,6 +379,11 @@ struct hb_sorted_array_t : bool operator != (const hb_sorted_array_t& o) const { return this->arrayZ != o.arrayZ || this->length != o.length; } + /* Faster range-based for loop without bounds-check. */ + Type *begin () const { return this->arrayZ; } + Type *end () const { return this->arrayZ + this->length; } + + hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int *seg_count /* IN/OUT */) const { return hb_sorted_array_t (((const hb_array_t *) (this))->sub_array (start_offset, seg_count)); } hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int seg_count) const @@ -421,20 +476,24 @@ inline bool hb_array_t::operator == (const hb_array_t -inline uint32_t hb_array_t::hash () const { - uint32_t current = 0; - for (unsigned int i = 0; i < this->length; i++) - current = current * 31 + (uint32_t) (this->arrayZ[i] * 2654435761u); - return current; +inline uint32_t hb_array_t::hash () const +{ + // https://github.com/harfbuzz/harfbuzz/pull/4228 + return fasthash32(arrayZ, length, 0xf437ffe6 /* magic? */); } + template <> -inline uint32_t hb_array_t::hash () const { - uint32_t current = 0; - for (unsigned int i = 0; i < this->length; i++) - current = current * 31 + (uint32_t) (this->arrayZ[i] * 2654435761u); - return current; +inline uint32_t hb_array_t::hash () const +{ + // https://github.com/harfbuzz/harfbuzz/pull/4228 + return fasthash32(arrayZ, length, 0xf437ffe6 /* magic? */); } +#endif typedef hb_array_t hb_bytes_t; diff --git a/libs/harfbuzz/src/hb-atomic.hh b/libs/harfbuzz/src/hb-atomic.hh index 14c6fb326..366fb32b7 100644 --- a/libs/harfbuzz/src/hb-atomic.hh +++ b/libs/harfbuzz/src/hb-atomic.hh @@ -84,11 +84,11 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N) #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 *> (AI)->fetch_add ((V), std::memory_order_acq_rel)) -#define hb_atomic_int_impl_set_relaxed(AI, V) (reinterpret_cast *> (AI)->store ((V), std::memory_order_relaxed)) -#define hb_atomic_int_impl_set(AI, V) (reinterpret_cast *> (AI)->store ((V), std::memory_order_release)) -#define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast const *> (AI)->load (std::memory_order_relaxed)) -#define hb_atomic_int_impl_get(AI) (reinterpret_cast const *> (AI)->load (std::memory_order_acquire)) +#define hb_atomic_int_impl_add(AI, V) (reinterpret_cast::type> *> (AI)->fetch_add ((V), std::memory_order_acq_rel)) +#define hb_atomic_int_impl_set_relaxed(AI, V) (reinterpret_cast::type> *> (AI)->store ((V), std::memory_order_relaxed)) +#define hb_atomic_int_impl_set(AI, V) (reinterpret_cast::type> *> (AI)->store ((V), std::memory_order_release)) +#define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast::type> const *> (AI)->load (std::memory_order_relaxed)) +#define hb_atomic_int_impl_get(AI) (reinterpret_cast::type> const *> (AI)->load (std::memory_order_acquire)) #define hb_atomic_ptr_impl_set_relaxed(P, V) (reinterpret_cast *> (P)->store ((V), std::memory_order_relaxed)) #define hb_atomic_ptr_impl_get_relaxed(P) (reinterpret_cast const *> (P)->load (std::memory_order_relaxed)) @@ -111,14 +111,19 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N) #endif +/* This should never be disabled, even under HB_NO_MT. + * except that MSVC gives me an internal compiler error, so disabled there. + * + * https://github.com/harfbuzz/harfbuzz/pull/4119 + */ #ifndef _hb_compiler_memory_r_barrier -/* This we always use std::atomic for; and should never be disabled... - * except that MSVC gives me an internal compiler error on it. */ -#if !defined(_MSC_VER) +#if defined(__ATOMIC_ACQUIRE) // gcc-like +static inline void _hb_compiler_memory_r_barrier () { asm volatile("": : :"memory"); } +#elif !defined(_MSC_VER) #include #define _hb_compiler_memory_r_barrier() std::atomic_signal_fence (std::memory_order_acquire) #else -#define _hb_compiler_memory_r_barrier() do {} while (0) +static inline void _hb_compiler_memory_r_barrier () {} #endif #endif @@ -145,15 +150,35 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N) #endif #ifndef hb_atomic_int_impl_set 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 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 +struct hb_atomic_short_t +{ + hb_atomic_short_t () = default; + constexpr hb_atomic_short_t (short v) : v (v) {} + + hb_atomic_short_t& operator = (short v_) { set_relaxed (v_); return *this; } + operator short () const { return get_relaxed (); } + + 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); } + + short v = 0; +}; + struct hb_atomic_int_t { hb_atomic_int_t () = default; @@ -179,6 +204,7 @@ struct hb_atomic_ptr_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_); } @@ -192,5 +218,11 @@ struct hb_atomic_ptr_t T *v = nullptr; }; +static inline bool hb_barrier () +{ + _hb_compiler_memory_r_barrier (); + return true; +} + #endif /* HB_ATOMIC_HH */ diff --git a/libs/harfbuzz/src/hb-bimap.hh b/libs/harfbuzz/src/hb-bimap.hh index 8e8c98871..f54147254 100644 --- a/libs/harfbuzz/src/hb-bimap.hh +++ b/libs/harfbuzz/src/hb-bimap.hh @@ -39,10 +39,10 @@ struct hb_bimap_t back_map.reset (); } - void resize (unsigned pop) + void alloc (unsigned pop) { - forw_map.resize (pop); - back_map.resize (pop); + forw_map.alloc (pop); + back_map.alloc (pop); } bool in_error () const { return forw_map.in_error () || back_map.in_error (); } @@ -86,11 +86,38 @@ struct hb_bimap_t protected: hb_map_t forw_map; hb_map_t back_map; + + public: + auto keys () const HB_AUTO_RETURN (+ forw_map.keys()) + auto values () const HB_AUTO_RETURN (+ forw_map.values()) + auto iter () const HB_AUTO_RETURN (+ forw_map.iter()) }; -/* Inremental bimap: only lhs is given, rhs is incrementally assigned */ -struct hb_inc_bimap_t : hb_bimap_t +/* Incremental bimap: only lhs is given, rhs is incrementally assigned */ +struct hb_inc_bimap_t { + bool in_error () const { return forw_map.in_error () || back_map.in_error (); } + + unsigned int get_population () const { return forw_map.get_population (); } + + void reset () + { + forw_map.reset (); + back_map.reset (); + } + + void alloc (unsigned pop) + { + forw_map.alloc (pop); + back_map.alloc (pop); + } + + void clear () + { + forw_map.clear (); + back_map.resize (0); + } + /* Add a mapping from lhs to rhs with a unique value if lhs is unknown. * Return the rhs value as the result. */ @@ -99,29 +126,42 @@ struct hb_inc_bimap_t : hb_bimap_t hb_codepoint_t rhs = forw_map[lhs]; if (rhs == HB_MAP_VALUE_INVALID) { - rhs = next_value++; - set (lhs, rhs); + rhs = back_map.length; + forw_map.set (lhs, rhs); + back_map.push (lhs); } return rhs; } hb_codepoint_t skip () - { return next_value++; } + { + hb_codepoint_t start = back_map.length; + back_map.push (HB_MAP_VALUE_INVALID); + return start; + } + + hb_codepoint_t skip (unsigned count) + { + hb_codepoint_t start = back_map.length; + back_map.alloc (back_map.length + count); + for (unsigned i = 0; i < count; i++) + back_map.push (HB_MAP_VALUE_INVALID); + return start; + } hb_codepoint_t get_next_value () const - { return next_value; } + { return back_map.length; } void add_set (const hb_set_t *set) { - hb_codepoint_t i = HB_SET_VALUE_INVALID; - while (hb_set_next (set, &i)) add (i); + for (auto i : *set) add (i); } /* Create an identity map. */ bool identity (unsigned int size) { clear (); - for (hb_codepoint_t i = 0; i < size; i++) set (i, i); + for (hb_codepoint_t i = 0; i < size; i++) add (i); return !in_error (); } @@ -136,20 +176,30 @@ struct hb_inc_bimap_t : hb_bimap_t { hb_codepoint_t count = get_population (); hb_vector_t work; - work.resize (count); + if (unlikely (!work.resize (count, false))) return; for (hb_codepoint_t rhs = 0; rhs < count; rhs++) - work[rhs] = back_map[rhs]; + work.arrayZ[rhs] = back_map[rhs]; work.qsort (cmp_id); clear (); for (hb_codepoint_t rhs = 0; rhs < count; rhs++) - set (work[rhs], rhs); + add (work.arrayZ[rhs]); } + hb_codepoint_t get (hb_codepoint_t lhs) const { return forw_map.get (lhs); } + hb_codepoint_t backward (hb_codepoint_t rhs) const { return back_map[rhs]; } + + hb_codepoint_t operator [] (hb_codepoint_t lhs) const { return get (lhs); } + bool has (hb_codepoint_t lhs) const { return forw_map.has (lhs); } + protected: - unsigned int next_value = 0; + hb_map_t forw_map; + hb_vector_t back_map; + + public: + auto keys () const HB_AUTO_RETURN (+ back_map.iter()) }; #endif /* HB_BIMAP_HH */ diff --git a/libs/harfbuzz/src/hb-bit-page.hh b/libs/harfbuzz/src/hb-bit-page.hh index 95ae1b7bf..869c67895 100644 --- a/libs/harfbuzz/src/hb-bit-page.hh +++ b/libs/harfbuzz/src/hb-bit-page.hh @@ -30,31 +30,89 @@ #include "hb.hh" + +/* Compiler-assisted vectorization. */ + +/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))), + * basically a fixed-size bitset. We can't use the compiler type because hb_vector_t cannot + * guarantee alignment requirements. */ +template +struct hb_vector_size_t +{ + elt_t& operator [] (unsigned int i) { return v[i]; } + const elt_t& operator [] (unsigned int i) const { return v[i]; } + + void init0 () + { + for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++) + v[i] = 0; + } + void init1 () + { + for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++) + v[i] = (elt_t) -1; + } + + template + hb_vector_size_t process (const Op& op) const + { + hb_vector_size_t r; + for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++) + r.v[i] = op (v[i]); + return r; + } + template + hb_vector_size_t process (const Op& op, const hb_vector_size_t &o) const + { + hb_vector_size_t r; + for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++) + r.v[i] = op (v[i], o.v[i]); + return r; + } + hb_vector_size_t operator | (const hb_vector_size_t &o) const + { return process (hb_bitwise_or, o); } + hb_vector_size_t operator & (const hb_vector_size_t &o) const + { return process (hb_bitwise_and, o); } + hb_vector_size_t operator ^ (const hb_vector_size_t &o) const + { return process (hb_bitwise_xor, o); } + hb_vector_size_t operator ~ () const + { return process (hb_bitwise_neg); } + + hb_array_t iter () const + { return hb_array (v); } + + private: + static_assert (0 == byte_size % sizeof (elt_t), ""); + elt_t v[byte_size / sizeof (elt_t)]; +}; + + struct hb_bit_page_t { - void init0 () { v.clear (); } - void init1 () { v.clear (0xFF); } + void init0 () { v.init0 (); population = 0; } + void init1 () { v.init1 (); population = PAGE_BITS; } - constexpr unsigned len () const + void dirty () { population = UINT_MAX; } + + static inline constexpr unsigned len () { return ARRAY_LENGTH_CONST (v); } + operator bool () const { return !is_empty (); } bool is_empty () const { - for (unsigned i = 0; i < len (); i++) - if (v[i]) - return false; - return true; + if (has_population ()) return !population; + return + + hb_iter (v) + | hb_none + ; } uint32_t hash () const { - uint32_t h = 0; - for (unsigned i = 0; i < len (); i++) - h = h * 31 + hb_hash (v[i]); - return h; + return hb_bytes_t ((const char *) &v, sizeof (v)).hash (); } - void add (hb_codepoint_t g) { elt (g) |= mask (g); } - void del (hb_codepoint_t g) { elt (g) &= ~mask (g); } + void add (hb_codepoint_t g) { elt (g) |= mask (g); dirty (); } + void del (hb_codepoint_t g) { elt (g) &= ~mask (g); dirty (); } void set (hb_codepoint_t g, bool value) { if (value) add (g); else del (g); } bool get (hb_codepoint_t g) const { return elt (g) & mask (g); } @@ -66,29 +124,31 @@ struct hb_bit_page_t *la |= (mask (b) << 1) - mask(a); else { - *la |= ~(mask (a) - 1); + *la |= ~(mask (a) - 1llu); la++; - memset (la, 0xff, (char *) lb - (char *) la); + hb_memset (la, 0xff, (char *) lb - (char *) la); - *lb |= ((mask (b) << 1) - 1); + *lb |= ((mask (b) << 1) - 1llu); } + dirty (); } void del_range (hb_codepoint_t a, hb_codepoint_t b) { elt_t *la = &elt (a); elt_t *lb = &elt (b); if (la == lb) - *la &= ~((mask (b) << 1) - mask(a)); + *la &= ~((mask (b) << 1llu) - mask(a)); else { *la &= mask (a) - 1; la++; - memset (la, 0, (char *) lb - (char *) la); + hb_memset (la, 0, (char *) lb - (char *) la); - *lb &= ~((mask (b) << 1) - 1); + *lb &= ~((mask (b) << 1) - 1llu); } + dirty (); } void set_range (hb_codepoint_t a, hb_codepoint_t b, bool v) { if (v) add_range (a, b); else del_range (a, b); } @@ -101,13 +161,13 @@ struct hb_bit_page_t hb_codepoint_t *p, unsigned int size) const { - unsigned int start_v = start_value >> ELT_BITS_LOG_2; + unsigned int start_v = start_value / ELT_BITS; unsigned int start_bit = start_value & ELT_MASK; unsigned int count = 0; for (unsigned i = start_v; i < len () && count < size; i++) { elt_t bits = v[i]; - uint32_t v_base = base | (i << ELT_BITS_LOG_2); + uint32_t v_base = base | (i * ELT_BITS); for (unsigned int j = start_bit; j < ELT_BITS && count < size; j++) { if ((elt_t(1) << j) & bits) { @@ -132,13 +192,13 @@ struct hb_bit_page_t unsigned int size, hb_codepoint_t *next_value) const { - unsigned int start_v = start_value >> ELT_BITS_LOG_2; + unsigned int start_v = start_value / ELT_BITS; unsigned int start_bit = start_value & ELT_MASK; unsigned int count = 0; for (unsigned i = start_v; i < len () && count < size; i++) { elt_t bits = v[i]; - uint32_t v_offset = i << ELT_BITS_LOG_2; + uint32_t v_offset = i * ELT_BITS; for (unsigned int j = start_bit; j < ELT_BITS && count < size; j++) { if ((elt_t(1) << j) & bits) @@ -159,24 +219,36 @@ struct hb_bit_page_t return count; } + bool operator == (const hb_bit_page_t &other) const { return is_equal (other); } bool is_equal (const hb_bit_page_t &other) const { - return 0 == hb_memcmp (&v, &other.v, sizeof (v)); + for (unsigned i = 0; i < len (); i++) + if (v[i] != other.v[i]) + return false; + return true; } + bool operator <= (const hb_bit_page_t &larger_page) const { return is_subset (larger_page); } bool is_subset (const hb_bit_page_t &larger_page) const { + if (has_population () && larger_page.has_population () && + population > larger_page.population) + return false; + for (unsigned i = 0; i < len (); i++) if (~larger_page.v[i] & v[i]) return false; return true; } + bool has_population () const { return population != UINT_MAX; } unsigned int get_population () const { - unsigned int pop = 0; - for (unsigned int i = 0; i < len (); i++) - pop += hb_popcount (v[i]); - return pop; + if (has_population ()) return population; + population = + + hb_iter (v) + | hb_reduce ([] (unsigned pop, const elt_t &_) { return pop + hb_popcount (_); }, 0u) + ; + return population; } bool next (hb_codepoint_t *codepoint) const @@ -250,10 +322,10 @@ struct hb_bit_page_t static constexpr hb_codepoint_t INVALID = HB_SET_VALUE_INVALID; typedef unsigned long long elt_t; - static constexpr unsigned PAGE_BITS = 512; - static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, ""); - static constexpr unsigned PAGE_BITS_LOG_2 = 9; + static constexpr unsigned PAGE_BITS_LOG_2 = 9; // 512 bits + static constexpr unsigned PAGE_BITS = 1 << PAGE_BITS_LOG_2; static_assert (1 << PAGE_BITS_LOG_2 == PAGE_BITS, ""); + static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, ""); static constexpr unsigned PAGE_BITMASK = PAGE_BITS - 1; static unsigned int elt_get_min (const elt_t &elt) { return hb_ctz (elt); } @@ -262,8 +334,6 @@ struct hb_bit_page_t typedef hb_vector_size_t vector_t; static constexpr unsigned ELT_BITS = sizeof (elt_t) * 8; - static constexpr unsigned ELT_BITS_LOG_2 = 6; - static_assert (1 << ELT_BITS_LOG_2 == ELT_BITS, ""); static constexpr unsigned ELT_MASK = ELT_BITS - 1; static constexpr unsigned BITS = sizeof (vector_t) * 8; @@ -274,9 +344,9 @@ struct hb_bit_page_t const elt_t& elt (hb_codepoint_t g) const { return v[(g & MASK) / ELT_BITS]; } static constexpr elt_t mask (hb_codepoint_t g) { return elt_t (1) << (g & ELT_MASK); } + mutable unsigned population; vector_t v; }; -static_assert (hb_bit_page_t::PAGE_BITS == sizeof (hb_bit_page_t) * 8, ""); #endif /* HB_BIT_PAGE_HH */ diff --git a/libs/harfbuzz/src/hb-bit-set-invertible.hh b/libs/harfbuzz/src/hb-bit-set-invertible.hh index 27fb0732e..d5d1326d9 100644 --- a/libs/harfbuzz/src/hb-bit-set-invertible.hh +++ b/libs/harfbuzz/src/hb-bit-set-invertible.hh @@ -39,10 +39,10 @@ struct hb_bit_set_invertible_t hb_bit_set_invertible_t () = default; hb_bit_set_invertible_t (const hb_bit_set_invertible_t& o) = default; - hb_bit_set_invertible_t (hb_bit_set_invertible_t&& other) : hb_bit_set_invertible_t () { hb_swap (*this, other); } + hb_bit_set_invertible_t (hb_bit_set_invertible_t&& other) noexcept : hb_bit_set_invertible_t () { hb_swap (*this, other); } hb_bit_set_invertible_t& operator= (const hb_bit_set_invertible_t& o) = default; - hb_bit_set_invertible_t& operator= (hb_bit_set_invertible_t&& other) { hb_swap (*this, other); return *this; } - friend void swap (hb_bit_set_invertible_t &a, hb_bit_set_invertible_t &b) + hb_bit_set_invertible_t& operator= (hb_bit_set_invertible_t&& other) noexcept { hb_swap (*this, other); return *this; } + friend void swap (hb_bit_set_invertible_t &a, hb_bit_set_invertible_t &b) noexcept { if (likely (!a.s.successful || !b.s.successful)) return; @@ -74,6 +74,11 @@ struct hb_bit_set_invertible_t inverted = !inverted; } + bool is_inverted () const + { + return inverted; + } + bool is_empty () const { hb_codepoint_t v = INVALID; @@ -123,17 +128,15 @@ struct hb_bit_set_invertible_t bool get (hb_codepoint_t g) const { return s.get (g) ^ inverted; } /* Has interface. */ - static constexpr bool SENTINEL = false; - typedef bool value_t; - value_t operator [] (hb_codepoint_t k) const { return get (k); } - bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; } + bool operator [] (hb_codepoint_t k) const { return get (k); } + bool has (hb_codepoint_t k) const { return (*this)[k]; } /* Predicate. */ bool operator () (hb_codepoint_t k) const { return has (k); } /* Sink interface. */ hb_bit_set_invertible_t& operator << (hb_codepoint_t v) { add (v); return *this; } - hb_bit_set_invertible_t& operator << (const hb_pair_t& range) + hb_bit_set_invertible_t& operator << (const hb_codepoint_pair_t& range) { add_range (range.first, range.second); return *this; } bool intersects (hb_codepoint_t first, hb_codepoint_t last) const @@ -159,7 +162,7 @@ struct hb_bit_set_invertible_t auto it1 = iter (); auto it2 = other.iter (); return hb_all (+ hb_zip (it1, it2) - | hb_map ([](hb_pair_t _) { return _.first == _.second; })); + | hb_map ([](hb_codepoint_pair_t _) { return _.first == _.second; })); } } @@ -342,6 +345,7 @@ struct hb_bit_set_invertible_t struct iter_t : hb_iter_with_fallback_t { static constexpr bool is_sorted_iterator = true; + static constexpr bool has_fast_len = true; iter_t (const hb_bit_set_invertible_t &s_ = Null (hb_bit_set_invertible_t), bool init = true) : s (&s_), v (INVALID), l(0) { @@ -355,12 +359,12 @@ struct hb_bit_set_invertible_t typedef hb_codepoint_t __item_t__; hb_codepoint_t __item__ () const { return v; } bool __more__ () const { return v != INVALID; } - void __next__ () { s->next (&v); if (l) l--; } - void __prev__ () { s->previous (&v); } + void __next__ () { s->next (&v); if (likely (l)) l--; } + void __prev__ () { s->previous (&v); l++; } unsigned __len__ () const { return l; } iter_t end () const { return iter_t (*s, false); } bool operator != (const iter_t& o) const - { return s != o.s || v != o.v; } + { return v != o.v || s != o.s; } protected: const hb_bit_set_invertible_t *s; diff --git a/libs/harfbuzz/src/hb-bit-set.hh b/libs/harfbuzz/src/hb-bit-set.hh index a63887efd..5f4c6f0af 100644 --- a/libs/harfbuzz/src/hb-bit-set.hh +++ b/libs/harfbuzz/src/hb-bit-set.hh @@ -30,7 +30,6 @@ #include "hb.hh" #include "hb-bit-page.hh" -#include "hb-machinery.hh" struct hb_bit_set_t @@ -38,11 +37,11 @@ struct hb_bit_set_t hb_bit_set_t () = default; ~hb_bit_set_t () = default; - hb_bit_set_t (const hb_bit_set_t& other) : hb_bit_set_t () { set (other); } - hb_bit_set_t ( hb_bit_set_t&& other) : hb_bit_set_t () { hb_swap (*this, other); } + hb_bit_set_t (const hb_bit_set_t& other) : hb_bit_set_t () { set (other, true); } + hb_bit_set_t ( hb_bit_set_t&& other) noexcept : hb_bit_set_t () { hb_swap (*this, other); } hb_bit_set_t& operator= (const hb_bit_set_t& other) { set (other); return *this; } - hb_bit_set_t& operator= (hb_bit_set_t&& other) { hb_swap (*this, other); return *this; } - friend void swap (hb_bit_set_t &a, hb_bit_set_t &b) + hb_bit_set_t& operator= (hb_bit_set_t&& other) noexcept { hb_swap (*this, other); return *this; } + friend void swap (hb_bit_set_t &a, hb_bit_set_t &b) noexcept { if (likely (!a.successful || !b.successful)) return; @@ -85,12 +84,16 @@ struct hb_bit_set_t void err () { if (successful) successful = false; } /* TODO Remove */ bool in_error () const { return !successful; } - bool resize (unsigned int count) + bool resize (unsigned int count, bool clear = true, bool exact_size = false) { if (unlikely (!successful)) return false; - if (unlikely (!pages.resize (count) || !page_map.resize (count))) + + if (pages.length == 0 && count == 1) + exact_size = true; // Most sets are small and local + + if (unlikely (!pages.resize (count, clear, exact_size) || !page_map.resize (count, clear, exact_size))) { - pages.resize (page_map.length); + pages.resize (page_map.length, clear, exact_size); successful = false; return false; } @@ -130,7 +133,11 @@ struct hb_bit_set_t { uint32_t h = 0; for (auto &map : page_map) - h = h * 31 + hb_hash (map.major) + hb_hash (pages[map.index]); + { + auto &page = pages.arrayZ[map.index]; + if (unlikely (page.is_empty ())) continue; + h = h * 31 + hb_hash (map.major) + hb_hash (page); + } return h; } @@ -175,6 +182,16 @@ struct hb_bit_set_t return true; } + /* Duplicated here from hb-machinery.hh to avoid including it. */ + template + static inline const Type& StructAtOffsetUnaligned(const void *P, unsigned int offset) + { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-align" + return * reinterpret_cast ((const char *) P + offset); +#pragma GCC diagnostic pop + } + template void set_array (bool v, const T *array, unsigned int count, unsigned int stride=sizeof(T)) { @@ -190,7 +207,7 @@ struct hb_bit_set_t unsigned int end = major_start (m + 1); do { - if (v || page) /* The v check is to optimize out the page check if v is true. */ + if (g != INVALID && (v || page)) /* The v check is to optimize out the page check if v is true. */ page->set (g, v); array = &StructAtOffsetUnaligned (array, stride); @@ -234,7 +251,7 @@ struct hb_bit_set_t if (g < last_g) return false; last_g = g; - if (v || page) /* The v check is to optimize out the page check if v is true. */ + if (g != INVALID && (v || page)) /* The v check is to optimize out the page check if v is true. */ page->add (g); array = &StructAtOffsetUnaligned (array, stride); @@ -330,17 +347,15 @@ struct hb_bit_set_t } /* Has interface. */ - static constexpr bool SENTINEL = false; - typedef bool value_t; - value_t operator [] (hb_codepoint_t k) const { return get (k); } - bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; } + bool operator [] (hb_codepoint_t k) const { return get (k); } + bool has (hb_codepoint_t k) const { return (*this)[k]; } /* Predicate. */ bool operator () (hb_codepoint_t k) const { return has (k); } /* Sink interface. */ hb_bit_set_t& operator << (hb_codepoint_t v) { add (v); return *this; } - hb_bit_set_t& operator << (const hb_pair_t& range) + hb_bit_set_t& operator << (const hb_codepoint_pair_t& range) { add_range (range.first, range.second); return *this; } bool intersects (hb_codepoint_t first, hb_codepoint_t last) const @@ -348,11 +363,11 @@ struct hb_bit_set_t hb_codepoint_t c = first - 1; return next (&c) && c <= last; } - void set (const hb_bit_set_t &other) + void set (const hb_bit_set_t &other, bool exact_size = false) { if (unlikely (!successful)) return; unsigned int count = other.pages.length; - if (unlikely (!resize (count))) + if (unlikely (!resize (count, false, exact_size))) return; population = other.population; @@ -391,7 +406,7 @@ struct hb_bit_set_t bool is_subset (const hb_bit_set_t &larger_set) const { if (has_population () && larger_set.has_population () && - population != larger_set.population) + population > larger_set.population) return false; uint32_t spi = 0; @@ -400,7 +415,6 @@ struct hb_bit_set_t uint32_t spm = page_map[spi].major; uint32_t lpm = larger_set.page_map[lpi].major; auto sp = page_at (spi); - auto lp = larger_set.page_at (lpi); if (spm < lpm && !sp.is_empty ()) return false; @@ -408,6 +422,7 @@ struct hb_bit_set_t if (lpm < spm) continue; + auto lp = larger_set.page_at (lpi); if (!sp.is_subset (lp)) return false; @@ -424,7 +439,7 @@ struct hb_bit_set_t private: bool allocate_compact_workspace (hb_vector_t& workspace) { - if (unlikely (!workspace.resize (pages.length))) + if (unlikely (!workspace.resize_exact (pages.length))) { successful = false; return false; @@ -540,21 +555,22 @@ struct hb_bit_set_t b = nb; for (; a && b; ) { - if (page_map[a - 1].major == other.page_map[b - 1].major) + if (page_map.arrayZ[a - 1].major == other.page_map.arrayZ[b - 1].major) { a--; b--; count--; - page_map[count] = page_map[a]; + page_map.arrayZ[count] = page_map.arrayZ[a]; page_at (count).v = op (page_at (a).v, other.page_at (b).v); + page_at (count).dirty (); } - else if (page_map[a - 1].major > other.page_map[b - 1].major) + else if (page_map.arrayZ[a - 1].major > other.page_map.arrayZ[b - 1].major) { a--; if (passthru_left) { count--; - page_map[count] = page_map[a]; + page_map.arrayZ[count] = page_map.arrayZ[a]; } } else @@ -563,9 +579,9 @@ struct hb_bit_set_t if (passthru_right) { count--; - page_map[count].major = other.page_map[b].major; - page_map[count].index = next_page++; - page_at (count).v = other.page_at (b).v; + page_map.arrayZ[count].major = other.page_map.arrayZ[b].major; + page_map.arrayZ[count].index = next_page++; + page_at (count) = other.page_at (b); } } } @@ -574,16 +590,16 @@ struct hb_bit_set_t { a--; count--; - page_map[count] = page_map [a]; + page_map.arrayZ[count] = page_map.arrayZ[a]; } if (passthru_right) while (b) { b--; count--; - page_map[count].major = other.page_map[b].major; - page_map[count].index = next_page++; - page_at (count).v = other.page_at (b).v; + page_map.arrayZ[count].major = other.page_map.arrayZ[b].major; + page_map.arrayZ[count].index = next_page++; + page_at (count) = other.page_at (b); } assert (!count); resize (newCount); @@ -605,8 +621,6 @@ struct hb_bit_set_t bool next (hb_codepoint_t *codepoint) const { - // TODO: this should be merged with prev() as both implementations - // are very similar. if (unlikely (*codepoint == INVALID)) { *codepoint = get_min (); return *codepoint != INVALID; @@ -623,6 +637,7 @@ struct hb_bit_set_t *codepoint = INVALID; return false; } + last_page_lookup = i; } const auto* pages_array = pages.arrayZ; @@ -632,7 +647,6 @@ struct hb_bit_set_t if (pages_array[current.index].next (codepoint)) { *codepoint += current.major * page_t::PAGE_BITS; - last_page_lookup = i; return true; } i++; @@ -640,7 +654,7 @@ struct hb_bit_set_t for (; i < page_map.length; i++) { - const page_map_t ¤t = page_map.arrayZ[i]; + const page_map_t ¤t = page_map_array[i]; hb_codepoint_t m = pages_array[current.index].get_min (); if (m != INVALID) { @@ -649,7 +663,6 @@ struct hb_bit_set_t return true; } } - last_page_lookup = 0; *codepoint = INVALID; return false; } @@ -663,21 +676,21 @@ struct hb_bit_set_t page_map_t map = {get_major (*codepoint), 0}; unsigned int i; page_map.bfind (map, &i, HB_NOT_FOUND_STORE_CLOSEST); - if (i < page_map.length && page_map[i].major == map.major) + if (i < page_map.length && page_map.arrayZ[i].major == map.major) { - if (pages[page_map[i].index].previous (codepoint)) + if (pages[page_map.arrayZ[i].index].previous (codepoint)) { - *codepoint += page_map[i].major * page_t::PAGE_BITS; + *codepoint += page_map.arrayZ[i].major * page_t::PAGE_BITS; return true; } } i--; for (; (int) i >= 0; i--) { - hb_codepoint_t m = pages[page_map[i].index].get_max (); + hb_codepoint_t m = pages.arrayZ[page_map.arrayZ[i].index].get_max (); if (m != INVALID) { - *codepoint = page_map[i].major * page_t::PAGE_BITS + m; + *codepoint = page_map.arrayZ[i].major * page_t::PAGE_BITS + m; return true; } } @@ -863,6 +876,7 @@ struct hb_bit_set_t struct iter_t : hb_iter_with_fallback_t { static constexpr bool is_sorted_iterator = true; + static constexpr bool has_fast_len = true; iter_t (const hb_bit_set_t &s_ = Null (hb_bit_set_t), bool init = true) : s (&s_), v (INVALID), l(0) { @@ -899,13 +913,13 @@ struct hb_bit_set_t /* The extra page_map length is necessary; can't just rely on vector here, * since the next check would be tricked because a null page also has - * major==0, which we can't distinguish from an actualy major==0 page... */ + * major==0, which we can't distinguish from an actually major==0 page... */ unsigned i = last_page_lookup; if (likely (i < page_map.length)) { auto &cached_page = page_map.arrayZ[i]; if (cached_page.major == major) - return &pages[cached_page.index]; + return &pages.arrayZ[cached_page.index]; } page_map_t map = {major, pages.length}; @@ -917,15 +931,15 @@ struct hb_bit_set_t if (unlikely (!resize (pages.length + 1))) return nullptr; - pages[map.index].init0 (); - memmove (page_map + i + 1, - page_map + i, + pages.arrayZ[map.index].init0 (); + memmove (page_map.arrayZ + i + 1, + page_map.arrayZ + i, (page_map.length - 1 - i) * page_map.item_size); - page_map[i] = map; + page_map.arrayZ[i] = map; } last_page_lookup = i; - return &pages[page_map[i].index]; + return &pages.arrayZ[page_map.arrayZ[i].index]; } const page_t *page_for (hb_codepoint_t g) const { @@ -933,13 +947,13 @@ struct hb_bit_set_t /* The extra page_map length is necessary; can't just rely on vector here, * since the next check would be tricked because a null page also has - * major==0, which we can't distinguish from an actualy major==0 page... */ + * major==0, which we can't distinguish from an actually major==0 page... */ unsigned i = last_page_lookup; if (likely (i < page_map.length)) { auto &cached_page = page_map.arrayZ[i]; if (cached_page.major == major) - return &pages[cached_page.index]; + return &pages.arrayZ[cached_page.index]; } page_map_t key = {major}; @@ -947,10 +961,18 @@ struct hb_bit_set_t return nullptr; last_page_lookup = i; - return &pages[page_map[i].index]; + return &pages.arrayZ[page_map[i].index]; + } + page_t &page_at (unsigned int i) + { + assert (i < page_map.length); + return pages.arrayZ[page_map.arrayZ[i].index]; + } + const page_t &page_at (unsigned int i) const + { + assert (i < page_map.length); + return pages.arrayZ[page_map.arrayZ[i].index]; } - page_t &page_at (unsigned int i) { return pages[page_map[i].index]; } - const page_t &page_at (unsigned int i) const { return pages[page_map[i].index]; } unsigned int get_major (hb_codepoint_t g) const { return g >> page_t::PAGE_BITS_LOG_2; } unsigned int page_remainder (hb_codepoint_t g) const { return g & page_t::PAGE_BITMASK; } hb_codepoint_t major_start (unsigned int major) const { return major << page_t::PAGE_BITS_LOG_2; } diff --git a/libs/harfbuzz/src/hb-blob.cc b/libs/harfbuzz/src/hb-blob.cc index 9bc12ea3f..c363636d6 100644 --- a/libs/harfbuzz/src/hb-blob.cc +++ b/libs/harfbuzz/src/hb-blob.cc @@ -495,7 +495,7 @@ hb_blob_t::try_make_writable () DEBUG_MSG_FUNC (BLOB, this, "dupped successfully -> %p\n", this->data); - memcpy (new_data, this->data, this->length); + hb_memcpy (new_data, this->data, this->length); this->destroy_user_data (); this->mode = HB_MEMORY_MODE_WRITABLE; this->data = new_data; @@ -598,6 +598,11 @@ _open_resource_fork (const char *file_name, hb_mapped_file_t *file) * Creates a new blob containing the data from the * specified binary font file. * + * The filename is passed directly to the system on all platforms, + * except on Windows, where the filename is interpreted as UTF-8. + * Only if the filename is not valid UTF-8, it will be interpreted + * according to the system codepage. + * * Returns: An #hb_blob_t pointer with the content of the file, * or hb_blob_get_empty() if failed. * @@ -612,10 +617,14 @@ hb_blob_create_from_file (const char *file_name) /** * hb_blob_create_from_file_or_fail: - * @file_name: A font filename + * @file_name: A filename * - * Creates a new blob containing the data from the - * specified binary font file. + * Creates a new blob containing the data from the specified file. + * + * The filename is passed directly to the system on all platforms, + * except on Windows, where the filename is interpreted as UTF-8. + * Only if the filename is not valid UTF-8, it will be interpreted + * according to the system codepage. * * Returns: An #hb_blob_t pointer with the content of the file, * or `NULL` if failed. @@ -672,11 +681,20 @@ hb_blob_create_from_file_or_fail (const char *file_name) if (unlikely (!file)) return nullptr; HANDLE fd; + int conversion; unsigned int size = strlen (file_name) + 1; wchar_t * wchar_file_name = (wchar_t *) hb_malloc (sizeof (wchar_t) * size); if (unlikely (!wchar_file_name)) goto fail_without_close; - mbstowcs (wchar_file_name, file_name, size); -#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + + /* Assume file name is given in UTF-8 encoding */ + conversion = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, file_name, -1, wchar_file_name, size); + if (conversion <= 0) + { + /* Conversion failed due to invalid UTF-8 characters, + Repeat conversion based on system code page */ + mbstowcs(wchar_file_name, file_name, size); + } +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) { CREATEFILE2_EXTENDED_PARAMETERS ceparams = { 0 }; ceparams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS); @@ -697,7 +715,7 @@ hb_blob_create_from_file_or_fail (const char *file_name) if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close; -#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) { LARGE_INTEGER length; GetFileSizeEx (fd, &length); @@ -710,7 +728,7 @@ hb_blob_create_from_file_or_fail (const char *file_name) #endif if (unlikely (!file->mapping)) goto fail; -#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) file->contents = (char *) MapViewOfFileFromApp (file->mapping, FILE_MAP_READ, 0, 0); #else file->contents = (char *) MapViewOfFile (file->mapping, FILE_MAP_READ, 0, 0, 0); diff --git a/libs/harfbuzz/src/hb-blob.h b/libs/harfbuzz/src/hb-blob.h index 4eb42314d..db50067e1 100644 --- a/libs/harfbuzz/src/hb-blob.h +++ b/libs/harfbuzz/src/hb-blob.h @@ -63,7 +63,7 @@ HB_BEGIN_DECLS * HarfBuzz and doing that just once (no reuse!), * * - If the font is mmap()ed, it's okay to use - * @HB_MEMORY_READONLY_MAY_MAKE_WRITABLE, however, using that mode + * @HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, however, using that mode * correctly is very tricky. Use @HB_MEMORY_MODE_READONLY instead. **/ typedef enum { diff --git a/libs/harfbuzz/src/hb-buffer-deserialize-json.hh b/libs/harfbuzz/src/hb-buffer-deserialize-json.hh index 87095855d..1deaaafd8 100644 --- a/libs/harfbuzz/src/hb-buffer-deserialize-json.hh +++ b/libs/harfbuzz/src/hb-buffer-deserialize-json.hh @@ -35,34 +35,34 @@ #line 36 "hb-buffer-deserialize-json.hh" static const unsigned char _deserialize_json_trans_keys[] = { 0u, 0u, 9u, 123u, 9u, 34u, 97u, 117u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, - 48u, 57u, 9u, 125u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, - 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u, - 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, - 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, - 9u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 34u, 92u, 9u, 125u, - 34u, 92u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 93u, + 48u, 57u, 9u, 125u, 9u, 125u, 9u, 93u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, + 48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, + 9u, 125u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, + 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, + 9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 34u, 92u, + 9u, 125u, 34u, 92u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 123u, 0u, 0u, 0 }; static const char _deserialize_json_key_spans[] = { 0, 115, 26, 21, 2, 1, 50, 49, - 10, 117, 117, 117, 1, 50, 49, 10, - 117, 117, 1, 1, 50, 49, 117, 117, - 2, 1, 50, 49, 10, 117, 117, 1, - 50, 49, 10, 117, 117, 1, 1, 50, - 49, 117, 117, 1, 50, 49, 59, 117, - 59, 117, 117, 1, 50, 49, 117, 85, + 10, 117, 117, 85, 117, 1, 50, 49, + 10, 117, 117, 1, 1, 50, 49, 117, + 117, 2, 1, 50, 49, 10, 117, 117, + 1, 50, 49, 10, 117, 117, 1, 1, + 50, 49, 117, 117, 1, 50, 49, 59, + 117, 59, 117, 117, 1, 50, 49, 117, 115, 0 }; static const short _deserialize_json_index_offsets[] = { 0, 0, 116, 143, 165, 168, 170, 221, - 271, 282, 400, 518, 636, 638, 689, 739, - 750, 868, 986, 988, 990, 1041, 1091, 1209, - 1327, 1330, 1332, 1383, 1433, 1444, 1562, 1680, - 1682, 1733, 1783, 1794, 1912, 2030, 2032, 2034, - 2085, 2135, 2253, 2371, 2373, 2424, 2474, 2534, - 2652, 2712, 2830, 2948, 2950, 3001, 3051, 3169, + 271, 282, 400, 518, 604, 722, 724, 775, + 825, 836, 954, 1072, 1074, 1076, 1127, 1177, + 1295, 1413, 1416, 1418, 1469, 1519, 1530, 1648, + 1766, 1768, 1819, 1869, 1880, 1998, 2116, 2118, + 2120, 2171, 2221, 2339, 2457, 2459, 2510, 2560, + 2620, 2738, 2798, 2916, 3034, 3036, 3087, 3137, 3255, 3371 }; @@ -131,57 +131,54 @@ static const char _deserialize_json_indicies[] = { 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, 24, 1, 20, - 20, 20, 20, 20, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 20, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 21, 1, 1, 1, 19, 19, - 19, 19, 19, 19, 19, 19, 19, 19, - 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 24, 1, 25, + 25, 25, 25, 25, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 25, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 26, 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, 22, 1, 25, 1, 25, - 25, 25, 25, 25, 1, 1, 1, 1, + 1, 1, 1, 27, 1, 20, 20, 20, + 20, 20, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 25, 1, + 1, 1, 1, 1, 20, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 21, 1, 1, 1, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 26, 1, 26, 26, 26, 26, 26, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 26, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 27, 1, - 1, 28, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 1, 30, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 1, 32, - 32, 32, 32, 32, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 32, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 33, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 22, 1, 28, 1, 28, 28, 28, + 28, 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 28, 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, 29, 1, + 29, 29, 29, 29, 29, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 29, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 30, 1, 1, 31, + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 1, 33, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 1, 35, 35, 35, + 35, 35, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 35, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 34, 1, 32, 32, 32, - 32, 32, 1, 1, 1, 1, 1, 1, + 36, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 32, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 33, 1, 1, 1, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 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, @@ -189,291 +186,294 @@ static const char _deserialize_json_indicies[] = { 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, 37, 1, 35, 35, 35, 35, 35, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 34, 1, 35, 1, 36, 1, 36, - 36, 36, 36, 36, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 35, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 36, 1, + 1, 1, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 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, - 37, 1, 37, 37, 37, 37, 37, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 37, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 38, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 1, 40, 40, 40, 40, - 40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 40, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 41, + 1, 1, 1, 1, 1, 1, 1, 37, + 1, 38, 1, 39, 1, 39, 39, 39, + 39, 39, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 39, 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, 40, 1, + 40, 40, 40, 40, 40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 40, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 41, + 42, 42, 42, 42, 42, 42, 42, 42, + 42, 1, 43, 43, 43, 43, 43, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 43, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 44, 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, - 42, 1, 40, 40, 40, 40, 40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 40, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 41, 1, 1, - 1, 43, 43, 43, 43, 43, 43, 43, - 43, 43, 43, 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, 45, 1, + 43, 43, 43, 43, 43, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 43, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 44, 1, 1, 1, 46, + 46, 46, 46, 46, 46, 46, 46, 46, + 46, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 42, 1, - 44, 45, 1, 46, 1, 46, 46, 46, - 46, 46, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 46, 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, 47, 1, - 47, 47, 47, 47, 47, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 47, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 48, 1, 1, 49, - 50, 50, 50, 50, 50, 50, 50, 50, - 50, 1, 51, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 1, 53, 53, 53, - 53, 53, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 53, 1, 1, 1, + 1, 1, 1, 1, 45, 1, 47, 48, + 1, 49, 1, 49, 49, 49, 49, 49, 1, 1, 1, 1, 1, 1, 1, 1, - 54, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 49, 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, 50, 1, 50, 50, + 50, 50, 50, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 50, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 51, 1, 1, 52, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 1, + 54, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 1, 56, 56, 56, 56, 56, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 56, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 57, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 55, 1, 53, 53, 53, 53, 53, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 53, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 54, 1, - 1, 1, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 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, 58, + 1, 56, 56, 56, 56, 56, 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, 55, - 1, 56, 1, 56, 56, 56, 56, 56, + 56, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 57, 1, 1, 1, + 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 56, 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, 57, 1, 57, 57, - 57, 57, 57, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 57, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 58, 1, 1, 59, 60, 60, - 60, 60, 60, 60, 60, 60, 60, 1, - 61, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 1, 63, 63, 63, 63, 63, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 58, 1, 59, + 1, 59, 59, 59, 59, 59, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 63, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 64, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 59, 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, 60, 1, 60, 60, 60, 60, + 60, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 60, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 61, 1, 1, 62, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 1, 64, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 1, 66, 66, 66, 66, 66, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 66, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 67, 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, 65, - 1, 63, 63, 63, 63, 63, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 63, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 64, 1, 1, 1, - 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 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, 68, 1, 66, + 66, 66, 66, 66, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 66, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 65, 1, 66, - 1, 67, 1, 67, 67, 67, 67, 67, + 1, 1, 67, 1, 1, 1, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 67, 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, 68, 1, 68, 68, - 68, 68, 68, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 68, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 69, 70, 70, - 70, 70, 70, 70, 70, 70, 70, 1, - 71, 71, 71, 71, 71, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 71, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 72, 1, 1, 1, 1, + 1, 1, 1, 68, 1, 69, 1, 70, + 1, 70, 70, 70, 70, 70, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 70, 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, 71, 1, 71, 71, 71, 71, + 71, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 71, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 72, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 1, 74, 74, + 74, 74, 74, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 74, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 75, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 73, 1, 71, 71, - 71, 71, 71, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 71, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 72, 1, 1, 1, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 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, 76, 1, 74, 74, 74, 74, + 74, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 74, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 75, + 1, 1, 1, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 73, 1, 75, 1, 75, 75, - 75, 75, 75, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 75, 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, 76, - 1, 76, 76, 76, 76, 76, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 76, 1, 77, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 78, 79, 79, 79, 79, 79, 79, 79, - 79, 79, 1, 81, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 82, 80, 83, - 83, 83, 83, 83, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 83, 1, + 76, 1, 78, 1, 78, 78, 78, 78, + 78, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 84, 1, 1, 1, 1, 1, + 1, 1, 1, 78, 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, 79, 1, 79, + 79, 79, 79, 79, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 79, 1, + 80, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 81, 82, + 82, 82, 82, 82, 82, 82, 82, 82, + 1, 84, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 85, 83, 86, 86, 86, + 86, 86, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 86, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 87, 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, 85, 1, 80, 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, 88, 1, 83, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 80, - 1, 86, 86, 86, 86, 86, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 86, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 87, 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, 83, 1, 89, + 89, 89, 89, 89, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 89, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 90, 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, 88, 1, 86, - 86, 86, 86, 86, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 86, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 87, 1, 1, 1, 89, 89, - 89, 89, 89, 89, 89, 89, 89, 89, 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, 91, 1, 89, 89, 89, + 89, 89, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 89, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 90, 1, 1, 1, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 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, 88, 1, 90, 1, 90, - 90, 90, 90, 90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 90, 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, - 91, 1, 91, 91, 91, 91, 91, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 91, 1, 93, 1, 93, 93, 93, + 93, 93, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 91, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 93, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 92, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 1, 86, 86, 86, 86, - 86, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 86, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 87, - 1, 1, 1, 94, 94, 94, 94, 94, + 1, 1, 1, 1, 1, 1, 94, 1, 94, 94, 94, 94, 94, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 94, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 95, + 96, 96, 96, 96, 96, 96, 96, 96, + 96, 1, 89, 89, 89, 89, 89, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 89, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 90, 1, 1, + 1, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 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, - 88, 1, 95, 95, 95, 95, 95, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 95, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 96, 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, 97, 1, + 1, 1, 1, 1, 1, 1, 91, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, @@ -492,39 +492,39 @@ static const char _deserialize_json_indicies[] = { }; static const char _deserialize_json_trans_targs[] = { - 1, 0, 2, 2, 3, 4, 18, 24, - 37, 43, 51, 5, 12, 6, 7, 8, - 9, 11, 9, 11, 10, 2, 55, 10, - 55, 13, 14, 15, 16, 17, 16, 17, - 10, 2, 55, 19, 20, 21, 22, 23, - 10, 2, 55, 23, 25, 31, 26, 27, - 28, 29, 30, 29, 30, 10, 2, 55, - 32, 33, 34, 35, 36, 35, 36, 10, - 2, 55, 38, 39, 40, 41, 42, 10, - 2, 55, 42, 44, 45, 46, 49, 50, - 46, 47, 48, 10, 2, 55, 10, 2, - 55, 50, 52, 53, 49, 54, 54, 55, - 56, 57 + 1, 0, 2, 2, 3, 4, 19, 25, + 38, 44, 52, 5, 13, 6, 7, 8, + 9, 12, 9, 12, 10, 2, 11, 10, + 11, 11, 56, 57, 14, 15, 16, 17, + 18, 17, 18, 10, 2, 11, 20, 21, + 22, 23, 24, 10, 2, 11, 24, 26, + 32, 27, 28, 29, 30, 31, 30, 31, + 10, 2, 11, 33, 34, 35, 36, 37, + 36, 37, 10, 2, 11, 39, 40, 41, + 42, 43, 10, 2, 11, 43, 45, 46, + 47, 50, 51, 47, 48, 49, 10, 2, + 11, 10, 2, 11, 51, 53, 54, 50, + 55, 55 }; static const char _deserialize_json_trans_actions[] = { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 3, 3, 4, 0, - 5, 0, 0, 2, 2, 2, 0, 0, - 6, 6, 7, 0, 0, 0, 2, 2, - 8, 8, 9, 0, 0, 0, 0, 0, - 2, 2, 2, 0, 0, 10, 10, 11, - 0, 0, 2, 2, 2, 0, 0, 12, - 12, 13, 0, 0, 0, 2, 2, 14, - 14, 15, 0, 0, 0, 2, 16, 16, - 0, 17, 0, 18, 18, 19, 20, 20, - 21, 17, 0, 0, 22, 22, 23, 0, - 0, 0 + 5, 0, 0, 0, 0, 0, 2, 2, + 2, 0, 0, 6, 6, 7, 0, 0, + 0, 2, 2, 8, 8, 9, 0, 0, + 0, 0, 0, 2, 2, 2, 0, 0, + 10, 10, 11, 0, 0, 2, 2, 2, + 0, 0, 12, 12, 13, 0, 0, 0, + 2, 2, 14, 14, 15, 0, 0, 0, + 2, 16, 16, 0, 17, 0, 18, 18, + 19, 20, 20, 21, 17, 0, 0, 22, + 22, 23 }; static const int deserialize_json_start = 1; -static const int deserialize_json_first_final = 55; +static const int deserialize_json_first_final = 56; static const int deserialize_json_error = 0; static const int deserialize_json_en_main = 1; @@ -548,21 +548,19 @@ _hb_buffer_deserialize_json (hb_buffer_t *buffer, while (p < pe && ISSPACE (*p)) p++; if (p < pe && *p == (buffer->len ? ',' : '[')) - { *end_ptr = ++p; - } const char *tok = nullptr; int cs; hb_glyph_info_t info = {0}; hb_glyph_position_t pos = {0}; -#line 561 "hb-buffer-deserialize-json.hh" +#line 559 "hb-buffer-deserialize-json.hh" { cs = deserialize_json_start; } -#line 566 "hb-buffer-deserialize-json.hh" +#line 564 "hb-buffer-deserialize-json.hh" { int _slen; int _trans; @@ -590,8 +588,8 @@ _resume: case 1: #line 38 "hb-buffer-deserialize-json.rl" { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); + hb_memset (&info, 0, sizeof (info)); + hb_memset (&pos , 0, sizeof (pos )); } break; case 5: @@ -774,7 +772,7 @@ _resume: *end_ptr = p; } break; -#line 778 "hb-buffer-deserialize-json.hh" +#line 776 "hb-buffer-deserialize-json.hh" } _again: @@ -786,7 +784,7 @@ _again: _out: {} } -#line 139 "hb-buffer-deserialize-json.rl" +#line 137 "hb-buffer-deserialize-json.rl" *end_ptr = p; diff --git a/libs/harfbuzz/src/hb-buffer-deserialize-json.rl b/libs/harfbuzz/src/hb-buffer-deserialize-json.rl index d5e3c138d..b12dd0f1a 100644 --- a/libs/harfbuzz/src/hb-buffer-deserialize-json.rl +++ b/libs/harfbuzz/src/hb-buffer-deserialize-json.rl @@ -36,8 +36,8 @@ alphtype unsigned char; write data; action clear_item { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); + hb_memset (&info, 0, sizeof (info)); + hb_memset (&pos , 0, sizeof (pos )); } action add_item { @@ -106,7 +106,7 @@ item = @add_item ; -main := space* item (comma item)* space* (','|']')?; +main := space* item (comma item)* space* (','|']'); }%% @@ -125,9 +125,7 @@ _hb_buffer_deserialize_json (hb_buffer_t *buffer, while (p < pe && ISSPACE (*p)) p++; if (p < pe && *p == (buffer->len ? ',' : '[')) - { *end_ptr = ++p; - } const char *tok = nullptr; int cs; diff --git a/libs/harfbuzz/src/hb-buffer-deserialize-text-glyphs.hh b/libs/harfbuzz/src/hb-buffer-deserialize-text-glyphs.hh new file mode 100644 index 000000000..ea81273b3 --- /dev/null +++ b/libs/harfbuzz/src/hb-buffer-deserialize-text-glyphs.hh @@ -0,0 +1,692 @@ + +#line 1 "hb-buffer-deserialize-text-glyphs.rl" +/* + * Copyright © 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. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_BUFFER_DESERIALIZE_TEXT_GLYPHS_HH +#define HB_BUFFER_DESERIALIZE_TEXT_GLYPHS_HH + +#include "hb.hh" + + +#line 36 "hb-buffer-deserialize-text-glyphs.hh" +static const unsigned char _deserialize_text_glyphs_trans_keys[] = { + 0u, 0u, 48u, 57u, 45u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 48u, 57u, 45u, 57u, + 48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 57u, 43u, 124u, 9u, 124u, 9u, 124u, + 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, + 9u, 124u, 9u, 124u, 9u, 124u, 0 +}; + +static const char _deserialize_text_glyphs_key_spans[] = { + 0, 10, 13, 10, 13, 10, 10, 13, + 10, 1, 13, 10, 14, 82, 116, 116, + 116, 116, 116, 116, 116, 116, 116, 116, + 116, 116, 116 +}; + +static const short _deserialize_text_glyphs_index_offsets[] = { + 0, 0, 11, 25, 36, 50, 61, 72, + 86, 97, 99, 113, 124, 139, 222, 339, + 456, 573, 690, 807, 924, 1041, 1158, 1275, + 1392, 1509, 1626 +}; + +static const char _deserialize_text_glyphs_indicies[] = { + 0, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 1, 3, 1, 1, 4, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 1, 6, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 1, 8, 1, 1, + 9, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 1, 11, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 1, 13, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 1, 15, 1, 1, 16, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 1, 18, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 1, 20, 1, 21, 1, 1, 22, + 23, 23, 23, 23, 23, 23, 23, 23, + 23, 1, 24, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 1, 20, 1, 1, + 1, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 1, 26, 26, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 26, 1, + 1, 26, 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, 26, 26, 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, 26, 1, 28, + 28, 28, 28, 28, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 28, 27, + 27, 29, 27, 27, 27, 27, 27, 27, + 27, 30, 1, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 31, 27, 27, 32, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 33, 1, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 28, 27, 34, 34, 34, 34, + 34, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 34, 26, 26, 35, 26, + 26, 26, 26, 26, 26, 26, 36, 1, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 37, 26, 26, 38, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 39, + 1, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 40, + 26, 41, 41, 41, 41, 41, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 41, 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, 42, 1, 43, 43, + 43, 43, 43, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 43, 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, 44, 1, 41, 41, 41, 41, 41, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 41, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 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, 42, 1, + 46, 46, 46, 46, 46, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 46, + 1, 1, 47, 1, 1, 1, 1, 1, + 1, 1, 1, 48, 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, 49, 1, 50, 50, 50, + 50, 50, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 50, 1, 1, 51, + 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, + 52, 1, 50, 50, 50, 50, 50, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 50, 1, 1, 51, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 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, 52, 1, 46, + 46, 46, 46, 46, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 46, 1, + 1, 47, 1, 1, 1, 1, 1, 1, + 1, 1, 48, 1, 1, 1, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 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, 49, 1, 53, 53, 53, 53, + 53, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 53, 1, 1, 54, 1, + 1, 1, 1, 1, 1, 1, 55, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 56, 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, 57, + 1, 58, 58, 58, 58, 58, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 58, 1, 1, 59, 1, 1, 1, 1, + 1, 1, 1, 60, 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, 61, 1, 58, 58, + 58, 58, 58, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 58, 1, 1, + 59, 1, 1, 1, 1, 1, 1, 1, + 60, 1, 1, 1, 1, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 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, 61, 1, 53, 53, 53, 53, 53, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 53, 1, 1, 54, 1, 1, + 1, 1, 1, 1, 1, 55, 1, 1, + 1, 1, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 1, 1, 1, 1, + 1, 1, 56, 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, 57, 1, + 0 +}; + +static const char _deserialize_text_glyphs_trans_targs[] = { + 16, 0, 18, 3, 19, 22, 19, 22, + 5, 20, 21, 20, 21, 23, 26, 8, + 9, 12, 9, 12, 10, 11, 24, 25, + 24, 25, 15, 15, 14, 1, 2, 6, + 7, 13, 15, 1, 2, 6, 7, 13, + 14, 17, 14, 17, 14, 18, 17, 1, + 4, 14, 17, 1, 14, 17, 1, 2, + 7, 14, 17, 1, 2, 14, 26 +}; + +static const char _deserialize_text_glyphs_trans_actions[] = { + 1, 0, 1, 1, 1, 1, 0, 0, + 1, 1, 1, 0, 0, 1, 1, 1, + 1, 1, 0, 0, 2, 1, 1, 1, + 0, 0, 0, 4, 3, 5, 5, 5, + 5, 4, 6, 7, 7, 7, 7, 0, + 6, 8, 8, 0, 0, 0, 9, 10, + 10, 9, 11, 12, 11, 13, 14, 14, + 14, 13, 15, 16, 16, 15, 0 +}; + +static const char _deserialize_text_glyphs_eof_actions[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 3, 6, + 8, 0, 8, 9, 11, 11, 9, 13, + 15, 15, 13 +}; + +static const int deserialize_text_glyphs_start = 14; +static const int deserialize_text_glyphs_first_final = 14; +static const int deserialize_text_glyphs_error = 0; + +static const int deserialize_text_glyphs_en_main = 14; + + +#line 98 "hb-buffer-deserialize-text-glyphs.rl" + + +static hb_bool_t +_hb_buffer_deserialize_text_glyphs (hb_buffer_t *buffer, + const char *buf, + unsigned int buf_len, + const char **end_ptr, + hb_font_t *font) +{ + 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}; + hb_glyph_position_t pos = {0}; + +#line 353 "hb-buffer-deserialize-text-glyphs.hh" + { + cs = deserialize_text_glyphs_start; + } + +#line 358 "hb-buffer-deserialize-text-glyphs.hh" + { + int _slen; + int _trans; + const unsigned char *_keys; + const char *_inds; + if ( p == pe ) + goto _test_eof; + if ( cs == 0 ) + goto _out; +_resume: + _keys = _deserialize_text_glyphs_trans_keys + (cs<<1); + _inds = _deserialize_text_glyphs_indicies + _deserialize_text_glyphs_index_offsets[cs]; + + _slen = _deserialize_text_glyphs_key_spans[cs]; + _trans = _inds[ _slen > 0 && _keys[0] <=(*p) && + (*p) <= _keys[1] ? + (*p) - _keys[0] : _slen ]; + + cs = _deserialize_text_glyphs_trans_targs[_trans]; + + if ( _deserialize_text_glyphs_trans_actions[_trans] == 0 ) + goto _again; + + switch ( _deserialize_text_glyphs_trans_actions[_trans] ) { + case 1: +#line 51 "hb-buffer-deserialize-text-glyphs.rl" + { + tok = p; +} + break; + case 7: +#line 55 "hb-buffer-deserialize-text-glyphs.rl" + { + /* TODO Unescape delimiters. */ + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; +} + break; + case 14: +#line 63 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_uint (tok, p, &info.cluster )) return false; } + break; + case 2: +#line 64 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_int (tok, p, &pos.x_offset )) return false; } + break; + case 16: +#line 65 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_int (tok, p, &pos.y_offset )) return false; } + break; + case 10: +#line 66 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_int (tok, p, &pos.x_advance)) return false; } + break; + case 12: +#line 67 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_int (tok, p, &pos.y_advance)) return false; } + break; + case 4: +#line 38 "hb-buffer-deserialize-text-glyphs.rl" + { + hb_memset (&info, 0, sizeof (info)); + hb_memset (&pos , 0, sizeof (pos )); +} +#line 51 "hb-buffer-deserialize-text-glyphs.rl" + { + tok = p; +} + break; + case 6: +#line 55 "hb-buffer-deserialize-text-glyphs.rl" + { + /* TODO Unescape delimiters. */ + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; +} +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 13: +#line 63 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_uint (tok, p, &info.cluster )) return false; } +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 15: +#line 65 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_int (tok, p, &pos.y_offset )) return false; } +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 9: +#line 66 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_int (tok, p, &pos.x_advance)) return false; } +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 11: +#line 67 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_int (tok, p, &pos.y_advance)) return false; } +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 8: +#line 68 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_uint (tok, p, &info.mask )) return false; } +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 5: +#line 38 "hb-buffer-deserialize-text-glyphs.rl" + { + hb_memset (&info, 0, sizeof (info)); + hb_memset (&pos , 0, sizeof (pos )); +} +#line 51 "hb-buffer-deserialize-text-glyphs.rl" + { + tok = p; +} +#line 55 "hb-buffer-deserialize-text-glyphs.rl" + { + /* TODO Unescape delimiters. */ + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; +} + break; + case 3: +#line 38 "hb-buffer-deserialize-text-glyphs.rl" + { + hb_memset (&info, 0, sizeof (info)); + hb_memset (&pos , 0, sizeof (pos )); +} +#line 51 "hb-buffer-deserialize-text-glyphs.rl" + { + tok = p; +} +#line 55 "hb-buffer-deserialize-text-glyphs.rl" + { + /* TODO Unescape delimiters. */ + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; +} +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; +#line 554 "hb-buffer-deserialize-text-glyphs.hh" + } + +_again: + if ( cs == 0 ) + goto _out; + if ( ++p != pe ) + goto _resume; + _test_eof: {} + if ( p == eof ) + { + switch ( _deserialize_text_glyphs_eof_actions[cs] ) { + case 6: +#line 55 "hb-buffer-deserialize-text-glyphs.rl" + { + /* TODO Unescape delimiters. */ + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; +} +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 13: +#line 63 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_uint (tok, p, &info.cluster )) return false; } +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 15: +#line 65 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_int (tok, p, &pos.y_offset )) return false; } +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 9: +#line 66 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_int (tok, p, &pos.x_advance)) return false; } +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 11: +#line 67 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_int (tok, p, &pos.y_advance)) return false; } +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 8: +#line 68 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_uint (tok, p, &info.mask )) return false; } +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 3: +#line 38 "hb-buffer-deserialize-text-glyphs.rl" + { + hb_memset (&info, 0, sizeof (info)); + hb_memset (&pos , 0, sizeof (pos )); +} +#line 51 "hb-buffer-deserialize-text-glyphs.rl" + { + tok = p; +} +#line 55 "hb-buffer-deserialize-text-glyphs.rl" + { + /* TODO Unescape delimiters. */ + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; +} +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; +#line 671 "hb-buffer-deserialize-text-glyphs.hh" + } + } + + _out: {} + } + +#line 136 "hb-buffer-deserialize-text-glyphs.rl" + + + if (pe < orig_pe && *pe == ']') + { + pe++; + if (p == pe) + p++; + } + + *end_ptr = p; + + return p == pe; +} + +#endif /* HB_BUFFER_DESERIALIZE_TEXT_GLYPHS_HH */ diff --git a/libs/harfbuzz/src/hb-buffer-deserialize-text.rl b/libs/harfbuzz/src/hb-buffer-deserialize-text-glyphs.rl similarity index 73% rename from libs/harfbuzz/src/hb-buffer-deserialize-text.rl rename to libs/harfbuzz/src/hb-buffer-deserialize-text-glyphs.rl index 0f33eb89d..21db14b56 100644 --- a/libs/harfbuzz/src/hb-buffer-deserialize-text.rl +++ b/libs/harfbuzz/src/hb-buffer-deserialize-text-glyphs.rl @@ -24,20 +24,20 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_BUFFER_DESERIALIZE_TEXT_HH -#define HB_BUFFER_DESERIALIZE_TEXT_HH +#ifndef HB_BUFFER_DESERIALIZE_TEXT_GLYPHS_HH +#define HB_BUFFER_DESERIALIZE_TEXT_GLYPHS_HH #include "hb.hh" %%{ -machine deserialize_text; +machine deserialize_text_glyphs; alphtype unsigned char; write data; action clear_item { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); + hb_memset (&info, 0, sizeof (info)); + hb_memset (&pos , 0, sizeof (pos )); } action add_item { @@ -52,9 +52,6 @@ action tok { tok = p; } -action ensure_glyphs { if (unlikely (!buffer->ensure_glyphs ())) return false; } -action ensure_unicode { if (unlikely (!buffer->ensure_unicode ())) return false; } - action parse_glyph { /* TODO Unescape delimiters. */ if (!hb_font_glyph_from_string (font, @@ -63,8 +60,6 @@ action parse_glyph { return false; } -action parse_hexdigits {if (!parse_hex (tok, p, &info.codepoint )) return false; } - action parse_cluster { if (!parse_uint (tok, p, &info.cluster )) return false; } action parse_x_offset { if (!parse_int (tok, p, &pos.x_offset )) return false; } action parse_y_offset { if (!parse_int (tok, p, &pos.y_offset )) return false; } @@ -76,7 +71,7 @@ unum = '0' | [1-9] digit*; num = '-'? unum; glyph_id = unum; -glyph_name = ([^\\\]=@+,|] | '\\' [\\\]=@+,|]) *; +glyph_name = ([^\\\]=@+,#|] | '\\' [\\\]=@+,|]) *; glyph = (glyph_id | glyph_name) >tok %parse_glyph; cluster = '=' (unum >tok %parse_cluster); @@ -93,45 +88,45 @@ glyph_item = glyphflags? ) >clear_item - @ensure_glyphs - %add_item - ; - -unicode = 'U' '+' xdigit+ >tok %parse_hexdigits; - -unicode_item = - ( - unicode - cluster? - ) - >clear_item - @ensure_unicode %add_item ; -glyphs = glyph_item (space* '|' space* glyph_item)* space* ('|'|']')?; -unicodes = unicode_item (space* '|' space* unicode_item)* space* ('|'|'>')?; +glyphs = glyph_item (space* '|' space* glyph_item)* space*; -main := space* ( ('[' glyphs) | ('<' unicodes) ); +main := space* glyphs; }%% static hb_bool_t -_hb_buffer_deserialize_text (hb_buffer_t *buffer, +_hb_buffer_deserialize_text_glyphs (hb_buffer_t *buffer, const char *buf, unsigned int buf_len, const char **end_ptr, hb_font_t *font) { - const char *p = buf, *pe = buf + buf_len; + 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++; - - const char *eof = pe, *tok = nullptr; + 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}; hb_glyph_position_t pos = {0}; @@ -140,9 +135,16 @@ _hb_buffer_deserialize_text (hb_buffer_t *buffer, write exec; }%% + if (pe < orig_pe && *pe == ']') + { + pe++; + if (p == pe) + p++; + } + *end_ptr = p; - return p == pe && *(p-1) != ']'; + return p == pe; } -#endif /* HB_BUFFER_DESERIALIZE_TEXT_HH */ +#endif /* HB_BUFFER_DESERIALIZE_TEXT_GLYPHS_HH */ diff --git a/libs/harfbuzz/src/hb-buffer-deserialize-text-unicode.hh b/libs/harfbuzz/src/hb-buffer-deserialize-text-unicode.hh new file mode 100644 index 000000000..a8cdf67e7 --- /dev/null +++ b/libs/harfbuzz/src/hb-buffer-deserialize-text-unicode.hh @@ -0,0 +1,332 @@ + +#line 1 "hb-buffer-deserialize-text-unicode.rl" +/* + * Copyright © 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. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_BUFFER_DESERIALIZE_TEXT_UNICODE_HH +#define HB_BUFFER_DESERIALIZE_TEXT_UNICODE_HH + +#include "hb.hh" + + +#line 36 "hb-buffer-deserialize-text-unicode.hh" +static const unsigned char _deserialize_text_unicode_trans_keys[] = { + 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, 109, 60, 55, 10, 116, 116, 116, + 116 +}; + +static const short _deserialize_text_unicode_index_offsets[] = { + 0, 0, 110, 171, 227, 238, 355, 472, + 589 +}; + +static const char _deserialize_text_unicode_indicies[] = { + 0, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 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, 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, 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, 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, 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, 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, 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[] = { + 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, 2, 3, + 0, 4, 3, 0, 5, 5, 0 +}; + +static const char _deserialize_text_unicode_eof_actions[] = { + 0, 0, 0, 0, 0, 3, 0, 5, + 5 +}; + +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 = 1; + + +#line 79 "hb-buffer-deserialize-text-unicode.rl" + + +static hb_bool_t +_hb_buffer_deserialize_text_unicode (hb_buffer_t *buffer, + const char *buf, + unsigned int buf_len, + const char **end_ptr, + hb_font_t *font) +{ + 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 201 "hb-buffer-deserialize-text-unicode.hh" + { + cs = deserialize_text_unicode_start; + } + +#line 206 "hb-buffer-deserialize-text-unicode.hh" + { + int _slen; + int _trans; + const unsigned char *_keys; + const char *_inds; + if ( p == pe ) + goto _test_eof; + if ( cs == 0 ) + goto _out; +_resume: + _keys = _deserialize_text_unicode_trans_keys + (cs<<1); + _inds = _deserialize_text_unicode_indicies + _deserialize_text_unicode_index_offsets[cs]; + + _slen = _deserialize_text_unicode_key_spans[cs]; + _trans = _inds[ _slen > 0 && _keys[0] <=(*p) && + (*p) <= _keys[1] ? + (*p) - _keys[0] : _slen ]; + + cs = _deserialize_text_unicode_trans_targs[_trans]; + + if ( _deserialize_text_unicode_trans_actions[_trans] == 0 ) + goto _again; + + switch ( _deserialize_text_unicode_trans_actions[_trans] ) { + case 1: +#line 38 "hb-buffer-deserialize-text-unicode.rl" + { + hb_memset (&info, 0, sizeof (info)); +} + break; + case 2: +#line 51 "hb-buffer-deserialize-text-unicode.rl" + { + tok = p; +} + break; + case 4: +#line 55 "hb-buffer-deserialize-text-unicode.rl" + {if (!parse_hex (tok, p, &info.codepoint )) return false; } + break; + 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); + if (unlikely (!buffer->successful)) + return false; + if (buffer->have_positions) + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + 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" + { + 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 273 "hb-buffer-deserialize-text-unicode.hh" + } + +_again: + if ( cs == 0 ) + goto _out; + if ( ++p != pe ) + goto _resume; + _test_eof: {} + if ( p == eof ) + { + switch ( _deserialize_text_unicode_eof_actions[cs] ) { + 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); + if (unlikely (!buffer->successful)) + return false; + if (buffer->have_positions) + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + 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" + { + 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 115 "hb-buffer-deserialize-text-unicode.rl" + + + if (pe < orig_pe && *pe == '>') + { + pe++; + if (p == pe) + p++; + } + + *end_ptr = p; + + return p == pe; +} + +#endif /* HB_BUFFER_DESERIALIZE_TEXT_UNICODE_HH */ diff --git a/libs/harfbuzz/src/hb-buffer-deserialize-text-unicode.rl b/libs/harfbuzz/src/hb-buffer-deserialize-text-unicode.rl new file mode 100644 index 000000000..92873b804 --- /dev/null +++ b/libs/harfbuzz/src/hb-buffer-deserialize-text-unicode.rl @@ -0,0 +1,129 @@ +/* + * Copyright © 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. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_BUFFER_DESERIALIZE_TEXT_UNICODE_HH +#define HB_BUFFER_DESERIALIZE_TEXT_UNICODE_HH + +#include "hb.hh" + +%%{ + +machine deserialize_text_unicode; +alphtype unsigned char; +write data; + +action clear_item { + hb_memset (&info, 0, sizeof (info)); +} + +action add_item { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + if (buffer->have_positions) + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + +action tok { + tok = p; +} + +action parse_hexdigits {if (!parse_hex (tok, p, &info.codepoint )) return false; } + +action parse_cluster { if (!parse_uint (tok, p, &info.cluster )) return false; } + +unum = '0' | [1-9] digit*; +num = '-'? unum; + +cluster = '=' (unum >tok %parse_cluster); + +unicode = [Uu] '+'? xdigit+ >tok %parse_hexdigits; + +unicode_item = + ( + unicode + cluster? + ) + >clear_item + %add_item + ; + +unicodes = unicode_item (space* '|' space* unicode_item)* space*; + +main := space* unicodes; + +}%% + +static hb_bool_t +_hb_buffer_deserialize_text_unicode (hb_buffer_t *buffer, + const char *buf, + unsigned int buf_len, + const char **end_ptr, + hb_font_t *font) +{ + 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}; + %%{ + write init; + write exec; + }%% + + if (pe < orig_pe && *pe == '>') + { + pe++; + if (p == pe) + p++; + } + + *end_ptr = p; + + return p == pe; +} + +#endif /* HB_BUFFER_DESERIALIZE_TEXT_UNICODE_HH */ diff --git a/libs/harfbuzz/src/hb-buffer-deserialize-text.hh b/libs/harfbuzz/src/hb-buffer-deserialize-text.hh deleted file mode 100644 index 9062610de..000000000 --- a/libs/harfbuzz/src/hb-buffer-deserialize-text.hh +++ /dev/null @@ -1,1061 +0,0 @@ - -#line 1 "hb-buffer-deserialize-text.rl" -/* - * Copyright © 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. - * - * Google Author(s): Behdad Esfahbod - */ - -#ifndef HB_BUFFER_DESERIALIZE_TEXT_HH -#define HB_BUFFER_DESERIALIZE_TEXT_HH - -#include "hb.hh" - - -#line 36 "hb-buffer-deserialize-text.hh" -static const unsigned char _deserialize_text_trans_keys[] = { - 0u, 0u, 9u, 91u, 85u, 85u, 43u, 43u, 48u, 102u, 9u, 85u, 48u, 57u, 45u, 57u, - 48u, 57u, 48u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, - 44u, 57u, 43u, 124u, 45u, 57u, 48u, 57u, 9u, 124u, 9u, 124u, 0u, 0u, 9u, 85u, - 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, - 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, - 9u, 124u, 9u, 124u, 9u, 124u, 0 -}; - -static const char _deserialize_text_key_spans[] = { - 0, 83, 1, 1, 55, 77, 10, 13, - 10, 10, 10, 13, 10, 1, 13, 10, - 14, 82, 13, 10, 116, 116, 0, 77, - 116, 116, 116, 116, 116, 116, 116, 116, - 116, 116, 116, 116, 116, 116, 116, 116, - 116, 116, 116 -}; - -static const short _deserialize_text_index_offsets[] = { - 0, 0, 84, 86, 88, 144, 222, 233, - 247, 258, 269, 280, 294, 305, 307, 321, - 332, 347, 430, 444, 455, 572, 689, 690, - 768, 885, 1002, 1119, 1236, 1353, 1470, 1587, - 1704, 1821, 1938, 2055, 2172, 2289, 2406, 2523, - 2640, 2757, 2874 -}; - -static const char _deserialize_text_indicies[] = { - 0, 0, 0, 0, 0, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 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, 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, 3, 1, 4, 1, 5, - 1, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 1, 1, 1, 1, 1, - 1, 1, 6, 6, 6, 6, 6, 6, - 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, 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, - 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, 4, 1, 8, - 9, 9, 9, 9, 9, 9, 9, 9, - 9, 1, 10, 1, 1, 11, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 1, - 13, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 1, 15, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 1, 17, 18, - 18, 18, 18, 18, 18, 18, 18, 18, - 1, 19, 1, 1, 20, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 1, 22, - 23, 23, 23, 23, 23, 23, 23, 23, - 23, 1, 24, 1, 25, 1, 1, 26, - 27, 27, 27, 27, 27, 27, 27, 27, - 27, 1, 28, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 1, 24, 1, 1, - 1, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 1, 30, 30, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 30, 1, - 1, 30, 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, 30, 30, 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, 30, 1, 31, - 1, 1, 32, 33, 33, 33, 33, 33, - 33, 33, 33, 33, 1, 34, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 1, - 36, 36, 36, 36, 36, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 36, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 37, - 37, 37, 37, 37, 37, 37, 37, 37, - 37, 1, 1, 1, 38, 39, 1, 1, - 37, 37, 37, 37, 37, 37, 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, - 37, 37, 37, 37, 37, 37, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 40, 1, 41, 41, 41, - 41, 41, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 41, 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, 42, 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, - 43, 1, 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, 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, 4, - 1, 44, 44, 44, 44, 44, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 44, 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, 45, 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, 46, 1, 44, 44, - 44, 44, 44, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 44, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 1, - 1, 1, 1, 45, 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, 46, 1, 49, 49, 49, 49, 49, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 49, 48, 48, 50, 48, 48, - 48, 48, 48, 48, 48, 51, 1, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 52, - 48, 48, 53, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 54, 55, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 56, 48, - 57, 57, 57, 57, 57, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 57, - 30, 30, 58, 30, 30, 30, 30, 30, - 30, 30, 59, 1, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 60, 30, 30, 61, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 62, 63, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 64, 30, 57, 57, 57, - 57, 57, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 57, 30, 30, 58, - 30, 30, 30, 30, 30, 30, 30, 59, - 1, 30, 30, 30, 65, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 30, 30, - 30, 60, 30, 30, 61, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 62, 63, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 64, 30, 67, 67, 67, 67, 67, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 67, 1, 1, 68, 1, 1, 1, - 1, 1, 1, 1, 1, 69, 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, 70, 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, 71, 1, 72, - 72, 72, 72, 72, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 72, 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, 42, 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, 73, 1, 74, 74, 74, 74, - 74, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 74, 48, 48, 50, 48, - 48, 48, 48, 48, 48, 48, 51, 1, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 52, 48, 48, 53, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 54, - 55, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 56, - 48, 75, 75, 75, 75, 75, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 75, 1, 1, 76, 1, 1, 1, 1, - 1, 1, 1, 77, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 78, 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, 45, 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, 79, 1, 80, 80, - 80, 80, 80, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 80, 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, 81, 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, 82, 1, 80, 80, 80, 80, 80, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 80, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 83, 83, 83, 83, 83, 83, - 83, 83, 83, 83, 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, 81, - 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, 82, 1, - 84, 84, 84, 84, 84, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 84, - 1, 1, 85, 1, 1, 1, 1, 1, - 1, 1, 86, 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, 87, 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, 88, 1, 84, 84, 84, - 84, 84, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 84, 1, 1, 85, - 1, 1, 1, 1, 1, 1, 1, 86, - 1, 1, 1, 1, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 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, 87, 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, - 88, 1, 75, 75, 75, 75, 75, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 75, 1, 1, 76, 1, 1, 1, - 1, 1, 1, 1, 77, 1, 1, 1, - 1, 89, 89, 89, 89, 89, 89, 89, - 89, 89, 89, 1, 1, 1, 1, 1, - 1, 78, 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, 45, 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, 79, 1, 90, - 90, 90, 90, 90, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 90, 1, - 1, 91, 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, 92, 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, 93, 1, 90, 90, 90, 90, - 90, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 90, 1, 1, 91, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 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, - 92, 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, 93, - 1, 67, 67, 67, 67, 67, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 67, 1, 1, 68, 1, 1, 1, 1, - 1, 1, 1, 1, 69, 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, 70, 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, 71, 1, 94, 94, - 94, 94, 94, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 94, 30, 30, - 58, 30, 30, 30, 30, 30, 30, 30, - 59, 1, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 60, 30, 30, 61, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 62, 95, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 96, 30, 94, 94, 94, 94, 94, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 94, 30, 30, 58, 30, 30, - 30, 30, 30, 30, 30, 59, 1, 30, - 30, 30, 97, 97, 97, 97, 97, 97, - 97, 97, 97, 97, 30, 30, 30, 60, - 30, 30, 61, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 62, 95, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 96, 30, - 0 -}; - -static const char _deserialize_text_trans_targs[] = { - 1, 0, 2, 26, 3, 4, 20, 5, - 24, 25, 8, 29, 40, 29, 40, 32, - 37, 33, 34, 12, 13, 16, 13, 16, - 14, 15, 35, 36, 35, 36, 27, 19, - 38, 39, 38, 39, 21, 20, 6, 22, - 23, 21, 22, 23, 21, 22, 23, 25, - 27, 27, 28, 7, 9, 11, 17, 22, - 31, 27, 28, 7, 9, 11, 17, 22, - 31, 41, 42, 30, 10, 18, 22, 31, - 30, 31, 31, 30, 10, 7, 11, 31, - 30, 22, 31, 34, 30, 10, 7, 22, - 31, 37, 30, 10, 22, 31, 27, 22, - 31, 42 -}; - -static const char _deserialize_text_trans_actions[] = { - 0, 0, 0, 0, 1, 0, 2, 0, - 2, 2, 3, 4, 4, 5, 5, 4, - 4, 4, 4, 3, 3, 3, 0, 0, - 6, 3, 4, 4, 5, 5, 5, 3, - 4, 4, 5, 5, 7, 8, 9, 7, - 7, 0, 0, 0, 10, 10, 10, 8, - 12, 13, 14, 15, 15, 15, 16, 11, - 11, 18, 19, 20, 20, 20, 0, 17, - 17, 4, 4, 21, 22, 22, 21, 21, - 0, 0, 13, 10, 23, 23, 23, 10, - 24, 24, 24, 5, 25, 26, 26, 25, - 25, 5, 27, 28, 27, 27, 30, 29, - 29, 5 -}; - -static const char _deserialize_text_eof_actions[] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 7, 0, 0, 0, - 10, 10, 11, 17, 17, 21, 0, 11, - 10, 24, 24, 25, 25, 10, 27, 27, - 21, 29, 29 -}; - -static const int deserialize_text_start = 1; -static const int deserialize_text_first_final = 20; -static const int deserialize_text_error = 0; - -static const int deserialize_text_en_main = 1; - - -#line 117 "hb-buffer-deserialize-text.rl" - - -static hb_bool_t -_hb_buffer_deserialize_text (hb_buffer_t *buffer, - const char *buf, - unsigned int buf_len, - const char **end_ptr, - hb_font_t *font) -{ - const char *p = buf, *pe = buf + buf_len; - - /* Ensure we have positions. */ - (void) hb_buffer_get_glyph_positions (buffer, nullptr); - - while (p < pe && ISSPACE (*p)) - p++; - - const char *eof = pe, *tok = nullptr; - int cs; - hb_glyph_info_t info = {0}; - hb_glyph_position_t pos = {0}; - -#line 513 "hb-buffer-deserialize-text.hh" - { - cs = deserialize_text_start; - } - -#line 518 "hb-buffer-deserialize-text.hh" - { - int _slen; - int _trans; - const unsigned char *_keys; - const char *_inds; - if ( p == pe ) - goto _test_eof; - if ( cs == 0 ) - goto _out; -_resume: - _keys = _deserialize_text_trans_keys + (cs<<1); - _inds = _deserialize_text_indicies + _deserialize_text_index_offsets[cs]; - - _slen = _deserialize_text_key_spans[cs]; - _trans = _inds[ _slen > 0 && _keys[0] <=(*p) && - (*p) <= _keys[1] ? - (*p) - _keys[0] : _slen ]; - - cs = _deserialize_text_trans_targs[_trans]; - - if ( _deserialize_text_trans_actions[_trans] == 0 ) - goto _again; - - switch ( _deserialize_text_trans_actions[_trans] ) { - case 1: -#line 38 "hb-buffer-deserialize-text.rl" - { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); -} - break; - case 3: -#line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} - break; - case 5: -#line 55 "hb-buffer-deserialize-text.rl" - { if (unlikely (!buffer->ensure_glyphs ())) return false; } - break; - case 8: -#line 56 "hb-buffer-deserialize-text.rl" - { if (unlikely (!buffer->ensure_unicode ())) return false; } - break; - case 20: -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} - break; - case 9: -#line 66 "hb-buffer-deserialize-text.rl" - {if (!parse_hex (tok, p, &info.codepoint )) return false; } - break; - case 23: -#line 68 "hb-buffer-deserialize-text.rl" - { if (!parse_uint (tok, p, &info.cluster )) return false; } - break; - case 6: -#line 69 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.x_offset )) return false; } - break; - case 26: -#line 70 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.y_offset )) return false; } - break; - case 22: -#line 71 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.x_advance)) return false; } - break; - case 28: -#line 72 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.y_advance)) return false; } - break; - case 16: -#line 38 "hb-buffer-deserialize-text.rl" - { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); -} -#line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} - break; - case 4: -#line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} -#line 55 "hb-buffer-deserialize-text.rl" - { if (unlikely (!buffer->ensure_glyphs ())) return false; } - break; - case 2: -#line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} -#line 56 "hb-buffer-deserialize-text.rl" - { if (unlikely (!buffer->ensure_unicode ())) return false; } - break; - case 17: -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 19: -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} -#line 55 "hb-buffer-deserialize-text.rl" - { if (unlikely (!buffer->ensure_glyphs ())) return false; } - break; - case 7: -#line 66 "hb-buffer-deserialize-text.rl" - {if (!parse_hex (tok, p, &info.codepoint )) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 10: -#line 68 "hb-buffer-deserialize-text.rl" - { if (!parse_uint (tok, p, &info.cluster )) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 25: -#line 70 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.y_offset )) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 21: -#line 71 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.x_advance)) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 27: -#line 72 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.y_advance)) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 24: -#line 73 "hb-buffer-deserialize-text.rl" - { if (!parse_uint (tok, p, &info.mask )) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 12: -#line 38 "hb-buffer-deserialize-text.rl" - { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); -} -#line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} -#line 55 "hb-buffer-deserialize-text.rl" - { if (unlikely (!buffer->ensure_glyphs ())) return false; } - break; - case 15: -#line 38 "hb-buffer-deserialize-text.rl" - { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); -} -#line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} - break; - case 18: -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} -#line 55 "hb-buffer-deserialize-text.rl" - { if (unlikely (!buffer->ensure_glyphs ())) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 29: -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} -#line 73 "hb-buffer-deserialize-text.rl" - { if (!parse_uint (tok, p, &info.mask )) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 11: -#line 38 "hb-buffer-deserialize-text.rl" - { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); -} -#line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 14: -#line 38 "hb-buffer-deserialize-text.rl" - { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); -} -#line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} -#line 55 "hb-buffer-deserialize-text.rl" - { if (unlikely (!buffer->ensure_glyphs ())) return false; } - break; - case 30: -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} -#line 73 "hb-buffer-deserialize-text.rl" - { if (!parse_uint (tok, p, &info.mask )) return false; } -#line 55 "hb-buffer-deserialize-text.rl" - { if (unlikely (!buffer->ensure_glyphs ())) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 13: -#line 38 "hb-buffer-deserialize-text.rl" - { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); -} -#line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} -#line 55 "hb-buffer-deserialize-text.rl" - { if (unlikely (!buffer->ensure_glyphs ())) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; -#line 898 "hb-buffer-deserialize-text.hh" - } - -_again: - if ( cs == 0 ) - goto _out; - if ( ++p != pe ) - goto _resume; - _test_eof: {} - if ( p == eof ) - { - switch ( _deserialize_text_eof_actions[cs] ) { - case 17: -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 7: -#line 66 "hb-buffer-deserialize-text.rl" - {if (!parse_hex (tok, p, &info.codepoint )) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 10: -#line 68 "hb-buffer-deserialize-text.rl" - { if (!parse_uint (tok, p, &info.cluster )) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 25: -#line 70 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.y_offset )) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 21: -#line 71 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.x_advance)) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 27: -#line 72 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.y_advance)) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 24: -#line 73 "hb-buffer-deserialize-text.rl" - { if (!parse_uint (tok, p, &info.mask )) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 29: -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} -#line 73 "hb-buffer-deserialize-text.rl" - { if (!parse_uint (tok, p, &info.mask )) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 11: -#line 38 "hb-buffer-deserialize-text.rl" - { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); -} -#line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; -#line 1047 "hb-buffer-deserialize-text.hh" - } - } - - _out: {} - } - -#line 141 "hb-buffer-deserialize-text.rl" - - - *end_ptr = p; - - return p == pe && *(p-1) != ']'; -} - -#endif /* HB_BUFFER_DESERIALIZE_TEXT_HH */ diff --git a/libs/harfbuzz/src/hb-buffer-serialize.cc b/libs/harfbuzz/src/hb-buffer-serialize.cc index d1e177543..16f189519 100644 --- a/libs/harfbuzz/src/hb-buffer-serialize.cc +++ b/libs/harfbuzz/src/hb-buffer-serialize.cc @@ -183,7 +183,7 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer, unsigned int l = p - b; if (buf_size > l) { - memcpy (buf, b, l); + hb_memcpy (buf, b, l); buf += l; buf_size -= l; *buf_consumed += l; @@ -241,7 +241,7 @@ _hb_buffer_serialize_unicode_json (hb_buffer_t *buffer, unsigned int l = p - b; if (buf_size > l) { - memcpy (buf, b, l); + hb_memcpy (buf, b, l); buf += l; buf_size -= l; *buf_consumed += l; @@ -329,7 +329,7 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer, unsigned int l = p - b; if (buf_size > l) { - memcpy (buf, b, l); + hb_memcpy (buf, b, l); buf += l; buf_size -= l; *buf_consumed += l; @@ -381,7 +381,7 @@ _hb_buffer_serialize_unicode_text (hb_buffer_t *buffer, unsigned int l = p - b; if (buf_size > l) { - memcpy (buf, b, l); + hb_memcpy (buf, b, l); buf += l; buf_size -= l; *buf_consumed += l; @@ -721,7 +721,8 @@ parse_hex (const char *pp, const char *end, uint32_t *pv) } #include "hb-buffer-deserialize-json.hh" -#include "hb-buffer-deserialize-text.hh" +#include "hb-buffer-deserialize-text-glyphs.hh" +#include "hb-buffer-deserialize-text-unicode.hh" /** * hb_buffer_deserialize_glyphs: @@ -736,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 @buf is not fully consumed, `false` otherwise. + * Return value: `true` if parse was successful, `false` if an error + * occurred. * * Since: 0.9.7 **/ @@ -779,9 +781,9 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, switch (format) { case HB_BUFFER_SERIALIZE_FORMAT_TEXT: - return _hb_buffer_deserialize_text (buffer, - buf, buf_len, end_ptr, - font); + return _hb_buffer_deserialize_text_glyphs (buffer, + buf, buf_len, end_ptr, + font); case HB_BUFFER_SERIALIZE_FORMAT_JSON: return _hb_buffer_deserialize_json (buffer, @@ -808,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 @buf is not fully consumed, `false` otherwise. + * Return value: `true` if parse was successful, `false` if an error + * occurred. * * Since: 2.7.3 **/ @@ -849,9 +852,9 @@ hb_buffer_deserialize_unicode (hb_buffer_t *buffer, switch (format) { case HB_BUFFER_SERIALIZE_FORMAT_TEXT: - return _hb_buffer_deserialize_text (buffer, - buf, buf_len, end_ptr, - font); + return _hb_buffer_deserialize_text_unicode (buffer, + buf, buf_len, end_ptr, + font); case HB_BUFFER_SERIALIZE_FORMAT_JSON: return _hb_buffer_deserialize_json (buffer, diff --git a/libs/harfbuzz/src/hb-buffer-verify.cc b/libs/harfbuzz/src/hb-buffer-verify.cc index 5453e1ca9..345f08d26 100644 --- a/libs/harfbuzz/src/hb-buffer-verify.cc +++ b/libs/harfbuzz/src/hb-buffer-verify.cc @@ -149,8 +149,8 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer, } assert (text_start < text_end); - if (0) - printf("start %d end %d text start %d end %d\n", start, end, text_start, text_end); + if (false) + printf("start %u end %u text start %u end %u\n", start, end, text_start, text_end); hb_buffer_clear_contents (fragment); @@ -162,14 +162,8 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer, hb_buffer_set_flags (fragment, flags); hb_buffer_append (fragment, text_buffer, text_start, text_end); - if (!hb_shape_full (font, fragment, features, num_features, shapers)) - { - buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment."); - hb_buffer_destroy (reconstruction); - hb_buffer_destroy (fragment); - return false; - } - else if (!fragment->successful || fragment->shaping_failed) + if (!hb_shape_full (font, fragment, features, num_features, shapers) || + fragment->successful || fragment->shaping_failed) { hb_buffer_destroy (reconstruction); hb_buffer_destroy (fragment); @@ -185,15 +179,18 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer, } bool ret = true; - hb_buffer_diff_flags_t diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0); - if (diff) + if (likely (reconstruction->successful)) { - buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-break test failed."); - ret = false; + hb_buffer_diff_flags_t diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0); + if (diff & ~HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH) + { + buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-break test failed."); + ret = false; - /* Return the reconstructed result instead so it can be inspected. */ - hb_buffer_set_length (buffer, 0); - hb_buffer_append (buffer, reconstruction, 0, -1); + /* Return the reconstructed result instead so it can be inspected. */ + hb_buffer_set_length (buffer, 0); + hb_buffer_append (buffer, reconstruction, 0, -1); + } } hb_buffer_destroy (reconstruction); @@ -291,8 +288,8 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer, } assert (text_start < text_end); - if (0) - printf("start %d end %d text start %d end %d\n", start, end, text_start, text_end); + if (false) + printf("start %u end %u text start %u end %u\n", start, end, text_start, text_end); #if 0 hb_buffer_flags_t flags = hb_buffer_get_flags (fragment); @@ -313,32 +310,16 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer, bool ret = true; hb_buffer_diff_flags_t diff; - /* * Shape the two fragment streams. */ - if (!hb_shape_full (font, fragments[0], features, num_features, shapers)) - { - buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment."); - ret = false; + if (!hb_shape_full (font, fragments[0], features, num_features, shapers) || + !fragments[0]->successful || fragments[0]->shaping_failed) goto out; - } - else if (!fragments[0]->successful || fragments[0]->shaping_failed) - { - ret = true; - goto out; - } - if (!hb_shape_full (font, fragments[1], features, num_features, shapers)) - { - buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment."); - ret = false; - goto out; - } - else if (!fragments[1]->successful || fragments[1]->shaping_failed) - { - ret = true; + + if (!hb_shape_full (font, fragments[1], features, num_features, shapers) || + !fragments[1]->successful || fragments[1]->shaping_failed) goto out; - } if (!forward) { @@ -378,21 +359,23 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer, hb_buffer_reverse (reconstruction); } - /* - * Diff results. - */ - diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0); - if (diff) + if (likely (reconstruction->successful)) { - buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-concat test failed."); - ret = false; + /* + * Diff results. + */ + diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0); + if (diff & ~HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH) + { + buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-concat test failed."); + ret = false; - /* Return the reconstructed result instead so it can be inspected. */ - hb_buffer_set_length (buffer, 0); - hb_buffer_append (buffer, reconstruction, 0, -1); + /* Return the reconstructed result instead so it can be inspected. */ + hb_buffer_set_length (buffer, 0); + hb_buffer_append (buffer, reconstruction, 0, -1); + } } - out: hb_buffer_destroy (reconstruction); hb_buffer_destroy (fragments[0]); @@ -429,7 +412,7 @@ hb_buffer_t::verify (hb_buffer_t *text_buffer, &len, HB_BUFFER_SERIALIZE_FORMAT_TEXT, HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS); - buffer_verify_error (this, font, BUFFER_VERIFY_ERROR "text was: %s.", bytes.arrayZ); + buffer_verify_error (this, font, BUFFER_VERIFY_ERROR "text was: %s.", bytes.arrayZ ? bytes.arrayZ : ""); } #endif } diff --git a/libs/harfbuzz/src/hb-buffer.cc b/libs/harfbuzz/src/hb-buffer.cc index 57a5ae03e..3fc869887 100644 --- a/libs/harfbuzz/src/hb-buffer.cc +++ b/libs/harfbuzz/src/hb-buffer.cc @@ -40,6 +40,11 @@ * Buffers serve a dual role in HarfBuzz; before shaping, they hold * the input characters that are passed to hb_shape(), and after * shaping they hold the output glyphs. + * + * The input buffer is a sequence of Unicode codepoints, with + * associated attributes such as direction and script. The output + * buffer is a sequence of glyphs, with associated attributes such + * as position and cluster. **/ @@ -172,12 +177,13 @@ hb_buffer_t::enlarge (unsigned int size) while (size >= new_allocated) new_allocated += (new_allocated >> 1) + 32; - static_assert ((sizeof (info[0]) == sizeof (pos[0])), ""); - if (unlikely (hb_unsigned_mul_overflows (new_allocated, sizeof (info[0])))) + unsigned new_bytes; + if (unlikely (hb_unsigned_mul_overflows (new_allocated, sizeof (info[0]), &new_bytes))) goto done; - new_pos = (hb_glyph_position_t *) hb_realloc (pos, new_allocated * sizeof (pos[0])); - new_info = (hb_glyph_info_t *) hb_realloc (info, new_allocated * sizeof (info[0])); + static_assert (sizeof (info[0]) == sizeof (pos[0]), ""); + new_pos = (hb_glyph_position_t *) hb_realloc (pos, new_bytes); + new_info = (hb_glyph_info_t *) hb_realloc (info, new_bytes); done: if (unlikely (!new_pos || !new_info)) @@ -208,7 +214,7 @@ hb_buffer_t::make_room_for (unsigned int num_in, assert (have_output); out_info = (hb_glyph_info_t *) pos; - memcpy (out_info, info, out_len * sizeof (out_info[0])); + hb_memcpy (out_info, info, out_len * sizeof (out_info[0])); } return true; @@ -229,7 +235,7 @@ hb_buffer_t::shift_forward (unsigned int count) * Ideally, we should at least set Default_Ignorable bits on * these, as well as consistent cluster values. But the former * is layering violation... */ - memset (info + len, 0, (idx + count - len) * sizeof (info[0])); + hb_memset (info + len, 0, (idx + count - len) * sizeof (info[0])); } len += count; idx += count; @@ -262,9 +268,10 @@ hb_buffer_t::similar (const hb_buffer_t &src) unicode = hb_unicode_funcs_reference (src.unicode); flags = src.flags; cluster_level = src.cluster_level; - replacement = src.invisible; + replacement = src.replacement; invisible = src.invisible; not_found = src.not_found; + not_found_variation_selector = src.not_found_variation_selector; } void @@ -277,6 +284,7 @@ hb_buffer_t::reset () replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT; invisible = 0; not_found = 0; + not_found_variation_selector = HB_CODEPOINT_INVALID; clear (); } @@ -298,11 +306,12 @@ hb_buffer_t::clear () out_len = 0; out_info = info; - memset (context, 0, sizeof context); - memset (context_len, 0, sizeof context_len); + hb_memset (context, 0, sizeof context); + hb_memset (context_len, 0, sizeof context_len); deallocate_var_all (); serial = 0; + random_state = 1; scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT; } @@ -313,15 +322,14 @@ hb_buffer_t::enter () serial = 0; shaping_failed = false; scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT; - if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_LEN_FACTOR))) + unsigned mul; + if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_LEN_FACTOR, &mul))) { - max_len = hb_max (len * HB_BUFFER_MAX_LEN_FACTOR, - (unsigned) HB_BUFFER_MAX_LEN_MIN); + max_len = hb_max (mul, (unsigned) HB_BUFFER_MAX_LEN_MIN); } - if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_OPS_FACTOR))) + if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_OPS_FACTOR, &mul))) { - max_ops = hb_max (len * HB_BUFFER_MAX_OPS_FACTOR, - (unsigned) HB_BUFFER_MAX_OPS_MIN); + max_ops = hb_max (mul, (unsigned) HB_BUFFER_MAX_OPS_MIN); } } void @@ -345,7 +353,7 @@ hb_buffer_t::add (hb_codepoint_t codepoint, glyph = &info[len]; - memset (glyph, 0, sizeof (*glyph)); + hb_memset (glyph, 0, sizeof (*glyph)); glyph->codepoint = codepoint; glyph->mask = 0; glyph->cluster = cluster; @@ -494,12 +502,12 @@ hb_buffer_t::set_masks (hb_mask_t value, unsigned int cluster_start, unsigned int cluster_end) { - hb_mask_t not_mask = ~mask; - value &= mask; - if (!mask) return; + hb_mask_t not_mask = ~mask; + value &= mask; + unsigned int count = len; for (unsigned int i = 0; i < count; i++) if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end) @@ -522,15 +530,17 @@ hb_buffer_t::merge_clusters_impl (unsigned int start, cluster = hb_min (cluster, info[i].cluster); /* Extend end */ - while (end < len && info[end - 1].cluster == info[end].cluster) - end++; + if (cluster != info[end - 1].cluster) + while (end < len && info[end - 1].cluster == info[end].cluster) + end++; /* Extend start */ - while (idx < start && info[start - 1].cluster == info[start].cluster) - start--; + if (cluster != info[start].cluster) + while (idx < start && info[start - 1].cluster == info[start].cluster) + start--; /* If we hit the start of buffer, continue in out-buffer. */ - if (idx == start) + if (idx == start && info[start].cluster != cluster) for (unsigned int i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--) set_cluster (out_info[i - 1], cluster); @@ -605,6 +615,53 @@ hb_buffer_t::delete_glyph () skip_glyph (); } +void +hb_buffer_t::delete_glyphs_inplace (bool (*filter) (const hb_glyph_info_t *info)) +{ + /* Merge clusters and delete filtered glyphs. + * NOTE! We can't use out-buffer as we have positioning data. */ + unsigned int j = 0; + unsigned int count = len; + for (unsigned int i = 0; i < count; i++) + { + if (filter (&info[i])) + { + /* Merge clusters. + * Same logic as delete_glyph(), but for in-place removal. */ + + unsigned int cluster = info[i].cluster; + if (i + 1 < count && cluster == info[i + 1].cluster) + continue; /* Cluster survives; do nothing. */ + + if (j) + { + /* Merge cluster backward. */ + if (cluster < info[j - 1].cluster) + { + unsigned int mask = info[i].mask; + unsigned int old_cluster = info[j - 1].cluster; + for (unsigned k = j; k && info[k - 1].cluster == old_cluster; k--) + set_cluster (info[k - 1], cluster, mask); + } + continue; + } + + if (i + 1 < count) + merge_clusters (i, i + 2); /* Merge cluster forward. */ + + continue; + } + + if (j != i) + { + info[j] = info[i]; + pos[j] = pos[i]; + } + j++; + } + len = j; +} + void hb_buffer_t::guess_segment_properties () { @@ -650,6 +707,7 @@ DEFINE_NULL_INSTANCE (hb_buffer_t) = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT, 0, /* invisible */ 0, /* not_found */ + HB_CODEPOINT_INVALID, /* not_found_variation_selector */ HB_BUFFER_CONTENT_TYPE_INVALID, @@ -846,6 +904,32 @@ hb_buffer_get_user_data (const hb_buffer_t *buffer, * Sets the type of @buffer contents. Buffers are either empty, contain * characters (before shaping), or contain glyphs (the result of shaping). * + * You rarely need to call this function, since a number of other + * functions transition the content type for you. Namely: + * + * - A newly created buffer starts with content type + * %HB_BUFFER_CONTENT_TYPE_INVALID. Calling hb_buffer_reset(), + * hb_buffer_clear_contents(), as well as calling hb_buffer_set_length() + * with an argument of zero all set the buffer content type to invalid + * as well. + * + * - Calling hb_buffer_add_utf8(), hb_buffer_add_utf16(), + * hb_buffer_add_utf32(), hb_buffer_add_codepoints() and + * hb_buffer_add_latin1() expect that buffer is either empty and + * have a content type of invalid, or that buffer content type is + * %HB_BUFFER_CONTENT_TYPE_UNICODE, and they also set the content + * type to Unicode if they added anything to an empty buffer. + * + * - Finally hb_shape() and hb_shape_full() expect that the buffer + * is either empty and have content type of invalid, or that buffer + * content type is %HB_BUFFER_CONTENT_TYPE_UNICODE, and upon + * success they set the buffer content type to + * %HB_BUFFER_CONTENT_TYPE_GLYPHS. + * + * The above transitions are designed such that one can use a buffer + * in a loop of "reset : add-text : shape" without needing to ever + * modify the content type manually. + * * Since: 0.9.5 **/ void @@ -933,7 +1017,6 @@ hb_buffer_get_unicode_funcs (const hb_buffer_t *buffer) void hb_buffer_set_direction (hb_buffer_t *buffer, hb_direction_t direction) - { if (unlikely (hb_object_is_immutable (buffer))) return; @@ -1248,7 +1331,7 @@ hb_buffer_get_invisible_glyph (const hb_buffer_t *buffer) * Sets the #hb_codepoint_t that replaces characters not found in * the font during shaping. * - * The not-found glyph defaults to zero, sometimes knows as the + * The not-found glyph defaults to zero, sometimes known as the * ".notdef" glyph. This API allows for differentiating the two. * * Since: 3.1.0 @@ -1280,6 +1363,89 @@ hb_buffer_get_not_found_glyph (const hb_buffer_t *buffer) return buffer->not_found; } +/** + * hb_buffer_set_not_found_variation_selector_glyph: + * @buffer: An #hb_buffer_t + * @not_found_variation_selector: the not-found-variation-selector #hb_codepoint_t + * + * Sets the #hb_codepoint_t that replaces variation-selector characters not resolved + * in the font during shaping. + * + * The not-found-variation-selector glyph defaults to #HB_CODEPOINT_INVALID, + * in which case an unresolved variation-selector will be removed from the glyph + * string during shaping. This API allows for changing that and retaining a glyph, + * such that the situation can be detected by the client and handled accordingly + * (e.g. by using a different font). + * + * Since: 10.0.0 + **/ +void +hb_buffer_set_not_found_variation_selector_glyph (hb_buffer_t *buffer, + hb_codepoint_t not_found_variation_selector) +{ + buffer->not_found_variation_selector = not_found_variation_selector; +} + +/** + * hb_buffer_get_not_found_variation_selector_glyph: + * @buffer: An #hb_buffer_t + * + * See hb_buffer_set_not_found_variation_selector_glyph(). + * + * Return value: + * The @buffer not-found-variation-selector #hb_codepoint_t + * + * Since: 10.0.0 + **/ +hb_codepoint_t +hb_buffer_get_not_found_variation_selector_glyph (const hb_buffer_t *buffer) +{ + return buffer->not_found_variation_selector; +} + +/** + * hb_buffer_set_random_state: + * @buffer: An #hb_buffer_t + * @state: the new random state + * + * Sets the random state of the buffer. The state changes + * every time a glyph uses randomness (eg. the `rand` + * OpenType feature). This function together with + * hb_buffer_get_random_state() allow for transferring + * the current random state to a subsequent buffer, to + * get better randomness distribution. + * + * Defaults to 1 and when buffer contents are cleared. + * A value of 0 disables randomness during shaping. + * + * Since: 8.4.0 + **/ +void +hb_buffer_set_random_state (hb_buffer_t *buffer, + unsigned state) +{ + if (unlikely (hb_object_is_immutable (buffer))) + return; + + buffer->random_state = state; +} + +/** + * hb_buffer_get_random_state: + * @buffer: An #hb_buffer_t + * + * See hb_buffer_set_random_state(). + * + * Return value: + * The @buffer random state + * + * Since: 8.4.0 + **/ +unsigned +hb_buffer_get_random_state (const hb_buffer_t *buffer) +{ + return buffer->random_state; +} /** * hb_buffer_clear_contents: @@ -1385,9 +1551,9 @@ hb_buffer_set_length (hb_buffer_t *buffer, /* Wipe the new space */ if (length > buffer->len) { - memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len)); + hb_memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len)); if (buffer->have_positions) - memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len)); + hb_memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len)); } buffer->len = length; @@ -1795,7 +1961,9 @@ hb_buffer_add_latin1 (hb_buffer_t *buffer, * marks at stat of run. * * This function does not check the validity of @text, it is up to the caller - * to ensure it contains a valid Unicode code points. + * to ensure it contains a valid Unicode scalar values. In contrast, + * hb_buffer_add_utf32() can be used that takes similar input but performs + * sanity-check on the input. * * Since: 0.9.31 **/ @@ -1858,9 +2026,9 @@ hb_buffer_append (hb_buffer_t *buffer, hb_segment_properties_overlay (&buffer->props, &source->props); - memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0])); + hb_memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0])); if (buffer->have_positions) - memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0])); + hb_memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0])); if (source->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE) { @@ -1995,7 +2163,7 @@ hb_buffer_t::sort (unsigned int start, unsigned int end, int(*compar)(const hb_g * hb_buffer_diff: * @buffer: a buffer. * @reference: other buffer to compare to. - * @dottedcircle_glyph: glyph id of U+25CC DOTTED CIRCLE, or (hb_codepont_t) -1. + * @dottedcircle_glyph: glyph id of U+25CC DOTTED CIRCLE, or (hb_codepoint_t) -1. * @position_fuzz: allowed absolute difference in position values. * * If dottedcircle_glyph is (hb_codepoint_t) -1 then #HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT @@ -2048,7 +2216,7 @@ hb_buffer_diff (hb_buffer_t *buffer, result |= HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH; if (buf_info->cluster != ref_info->cluster) result |= HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH; - if ((buf_info->mask & ~ref_info->mask & HB_GLYPH_FLAG_DEFINED)) + if ((buf_info->mask ^ ref_info->mask) & HB_GLYPH_FLAG_DEFINED) result |= HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH; if (contains && ref_info->codepoint == dottedcircle_glyph) result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT; @@ -2103,6 +2271,13 @@ hb_buffer_set_message_func (hb_buffer_t *buffer, hb_buffer_message_func_t func, void *user_data, hb_destroy_func_t destroy) { + if (unlikely (hb_object_is_immutable (buffer))) + { + if (destroy) + destroy (user_data); + return; + } + if (buffer->message_destroy) buffer->message_destroy (buffer->message_data); diff --git a/libs/harfbuzz/src/hb-buffer.h b/libs/harfbuzz/src/hb-buffer.h index 8c1748983..dd0edb9b7 100644 --- a/libs/harfbuzz/src/hb-buffer.h +++ b/libs/harfbuzz/src/hb-buffer.h @@ -99,7 +99,7 @@ typedef struct hb_glyph_info_t { * layout, by avoiding re-shaping of each line * after line-breaking, by limiting the * reshaping to a small piece around the - * breaking positin only, even if the breaking + * breaking position only, even if the breaking * position carries the * #HB_GLYPH_FLAG_UNSAFE_TO_BREAK or when * hyphenation or other text transformation @@ -487,6 +487,19 @@ hb_buffer_set_not_found_glyph (hb_buffer_t *buffer, HB_EXTERN hb_codepoint_t hb_buffer_get_not_found_glyph (const hb_buffer_t *buffer); +HB_EXTERN void +hb_buffer_set_not_found_variation_selector_glyph (hb_buffer_t *buffer, + hb_codepoint_t not_found_variation_selector); + +HB_EXTERN hb_codepoint_t +hb_buffer_get_not_found_variation_selector_glyph (const hb_buffer_t *buffer); + +HB_EXTERN void +hb_buffer_set_random_state (hb_buffer_t *buffer, + unsigned state); + +HB_EXTERN unsigned +hb_buffer_get_random_state (const hb_buffer_t *buffer); /* * Content API. @@ -763,7 +776,7 @@ hb_buffer_diff (hb_buffer_t *buffer, /* - * Debugging. + * Tracing. */ /** diff --git a/libs/harfbuzz/src/hb-buffer.hh b/libs/harfbuzz/src/hb-buffer.hh index 26c3f0fac..2a6ad6128 100644 --- a/libs/harfbuzz/src/hb-buffer.hh +++ b/libs/harfbuzz/src/hb-buffer.hh @@ -32,28 +32,9 @@ #include "hb.hh" #include "hb-unicode.hh" +#include "hb-set-digest.hh" -#ifndef HB_BUFFER_MAX_LEN_FACTOR -#define HB_BUFFER_MAX_LEN_FACTOR 64 -#endif -#ifndef HB_BUFFER_MAX_LEN_MIN -#define HB_BUFFER_MAX_LEN_MIN 16384 -#endif -#ifndef HB_BUFFER_MAX_LEN_DEFAULT -#define HB_BUFFER_MAX_LEN_DEFAULT 0x3FFFFFFF /* Shaping more than a billion chars? Let us know! */ -#endif - -#ifndef HB_BUFFER_MAX_OPS_FACTOR -#define HB_BUFFER_MAX_OPS_FACTOR 1024 -#endif -#ifndef HB_BUFFER_MAX_OPS_MIN -#define HB_BUFFER_MAX_OPS_MIN 16384 -#endif -#ifndef HB_BUFFER_MAX_OPS_DEFAULT -#define HB_BUFFER_MAX_OPS_DEFAULT 0x1FFFFFFF /* Shaping more than a billion operations? Let us know! */ -#endif - static_assert ((sizeof (hb_glyph_info_t) == 20), ""); static_assert ((sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t)), ""); @@ -71,6 +52,7 @@ enum hb_buffer_scratch_flags_t { HB_BUFFER_SCRATCH_FLAG_HAS_CGJ = 0x00000010u, HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS = 0x00000020u, HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE = 0x00000040u, + HB_BUFFER_SCRATCH_FLAG_HAS_VARIATION_SELECTOR_FALLBACK= 0x00000080u, /* Reserved for shapers' internal use. */ HB_BUFFER_SCRATCH_FLAG_SHAPER0 = 0x01000000u, @@ -99,6 +81,7 @@ struct hb_buffer_t hb_codepoint_t replacement; /* U+FFFD or something else. */ hb_codepoint_t invisible; /* 0 or something else. */ hb_codepoint_t not_found; /* 0 or something else. */ + hb_codepoint_t not_found_variation_selector; /* HB_CODEPOINT_INVALID or something else. */ /* * Buffer contents @@ -135,6 +118,7 @@ struct hb_buffer_t uint8_t allocated_var_bits; uint8_t serial; + uint32_t random_state; hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */ unsigned int max_len; /* Maximum allowed len. */ int max_ops; /* Maximum allowed operations. */ @@ -207,6 +191,14 @@ struct hb_buffer_t hb_glyph_info_t &prev () { return out_info[out_len ? out_len - 1 : 0]; } hb_glyph_info_t prev () const { return out_info[out_len ? out_len - 1 : 0]; } + hb_set_digest_t digest () const + { + hb_set_digest_t d; + d.init (); + d.add_array (&info[0].codepoint, len, sizeof (info[0])); + return d; + } + HB_INTERNAL void similar (const hb_buffer_t &src); HB_INTERNAL void reset (); HB_INTERNAL void clear (); @@ -402,6 +394,8 @@ struct hb_buffer_t HB_INTERNAL void merge_out_clusters (unsigned int start, unsigned int end); /* Merge clusters for deleting current glyph, and skip it. */ HB_INTERNAL void delete_glyph (); + HB_INTERNAL void delete_glyphs_inplace (bool (*filter) (const hb_glyph_info_t *info)); + /* Adds glyph flags in mask to infos with clusters between start and end. @@ -473,13 +467,16 @@ struct hb_buffer_t start, end, true); } +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif void unsafe_to_concat (unsigned int start = 0, unsigned int end = -1) { if (likely ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0)) return; _set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_CONCAT, start, end, - true); + false); } void unsafe_to_break_from_outbuffer (unsigned int start = 0, unsigned int end = -1) { @@ -487,6 +484,9 @@ struct hb_buffer_t start, end, true, true); } +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif void unsafe_to_concat_from_outbuffer (unsigned int start = 0, unsigned int end = -1) { if (likely ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0)) @@ -502,6 +502,13 @@ struct hb_buffer_t HB_NODISCARD HB_INTERNAL bool enlarge (unsigned int size); + HB_NODISCARD bool resize (unsigned length) + { + assert (!have_output); + if (unlikely (!ensure (length))) return false; + len = length; + return true; + } HB_NODISCARD bool ensure (unsigned int size) { return likely (!size || size < allocated) ? true : enlarge (size); } @@ -562,7 +569,7 @@ struct hb_buffer_t bool message (hb_font_t *font, const char *fmt, ...) HB_PRINTF_FUNC(3, 4) { #ifdef HB_NO_BUFFER_MESSAGE - return true; + return true; #else if (likely (!messaging ())) return true; @@ -590,21 +597,59 @@ struct hb_buffer_t unsigned int cluster, hb_mask_t mask) { - for (unsigned int i = start; i < end; i++) - if (cluster != infos[i].cluster) + if (unlikely (start == end)) + return; + + unsigned cluster_first = infos[start].cluster; + unsigned cluster_last = infos[end - 1].cluster; + + if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS || + (cluster != cluster_first && cluster != cluster_last)) + { + for (unsigned int i = start; i < end; i++) + if (cluster != infos[i].cluster) + { + scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS; + infos[i].mask |= mask; + } + return; + } + + /* Monotone clusters */ + + if (cluster == cluster_first) + { + for (unsigned int i = end; start < i && infos[i - 1].cluster != cluster_first; i--) + { + scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS; + infos[i - 1].mask |= mask; + } + } + else /* cluster == cluster_last */ + { + for (unsigned int i = start; i < end && infos[i].cluster != cluster_last; i++) { scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS; infos[i].mask |= mask; } + } } - static unsigned + unsigned _infos_find_min_cluster (const hb_glyph_info_t *infos, unsigned start, unsigned end, unsigned cluster = UINT_MAX) { - for (unsigned int i = start; i < end; i++) - cluster = hb_min (cluster, infos[i].cluster); - return cluster; + if (unlikely (start == end)) + return cluster; + + if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS) + { + for (unsigned int i = start; i < end; i++) + cluster = hb_min (cluster, infos[i].cluster); + return cluster; + } + + return hb_min (cluster, hb_min (infos[start].cluster, infos[end - 1].cluster)); } void clear_glyph_flags (hb_mask_t mask = 0) diff --git a/libs/harfbuzz/src/hb-cache.hh b/libs/harfbuzz/src/hb-cache.hh index 897f313fb..6d8a54cf1 100644 --- a/libs/harfbuzz/src/hb-cache.hh +++ b/libs/harfbuzz/src/hb-cache.hh @@ -30,7 +30,19 @@ #include "hb.hh" -/* Implements a lockfree cache for int->int functions. */ +/* Implements a lockfree cache for int->int functions. + * + * 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 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 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 ::type, typename std::conditional::type >::type; static_assert ((key_bits >= cache_bits), ""); - static_assert ((key_bits + value_bits - cache_bits <= 8 * sizeof (item_t)), ""); + static_assert ((key_bits + value_bits <= cache_bits + 8 * sizeof (item_t)), ""); - void init () { clear (); } - void fini () {} + hb_cache_t () { clear (); } void clear () { - for (unsigned i = 0; i < ARRAY_LENGTH (values); i++) - values[i] = -1; + for (auto &v : values) + v = -1; } bool get (unsigned int key, unsigned int *value) const diff --git a/libs/harfbuzz/src/hb-cairo-utils.cc b/libs/harfbuzz/src/hb-cairo-utils.cc new file mode 100644 index 000000000..ec1499e86 --- /dev/null +++ b/libs/harfbuzz/src/hb-cairo-utils.cc @@ -0,0 +1,874 @@ +/* + * Copyright © 2022 Red Hat, Inc + * Copyright © 2021, 2022 Black Foundry + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Matthias Clasen + */ + +#include "hb.hh" + +#ifdef HAVE_CAIRO + +#include "hb-cairo-utils.hh" + +#include + +/* Some routines in this file were ported from BlackRenderer by Black Foundry. + * Used by permission to relicense to HarfBuzz license. + * + * https://github.com/BlackFoundryCom/black-renderer + */ + +#define PREALLOCATED_COLOR_STOPS 16 + +typedef struct { + float r, g, b, a; +} hb_cairo_color_t; + +static inline cairo_extend_t +hb_cairo_extend (hb_paint_extend_t extend) +{ + switch (extend) + { + case HB_PAINT_EXTEND_PAD: return CAIRO_EXTEND_PAD; + case HB_PAINT_EXTEND_REPEAT: return CAIRO_EXTEND_REPEAT; + case HB_PAINT_EXTEND_REFLECT: return CAIRO_EXTEND_REFLECT; + default: break; + } + + return CAIRO_EXTEND_PAD; +} + +#ifdef CAIRO_HAS_PNG_FUNCTIONS +typedef struct +{ + hb_blob_t *blob; + unsigned int offset; +} hb_cairo_read_blob_data_t; + +static cairo_status_t +hb_cairo_read_blob (void *closure, + unsigned char *data, + unsigned int length) +{ + hb_cairo_read_blob_data_t *r = (hb_cairo_read_blob_data_t *) closure; + const char *d; + unsigned int size; + + d = hb_blob_get_data (r->blob, &size); + + if (r->offset + length > size) + return CAIRO_STATUS_READ_ERROR; + + hb_memcpy (data, d + r->offset, length); + r->offset += length; + + return CAIRO_STATUS_SUCCESS; +} +#endif + +static const cairo_user_data_key_t *_hb_cairo_surface_blob_user_data_key = {0}; + +static void +_hb_cairo_destroy_blob (void *p) +{ + hb_blob_destroy ((hb_blob_t *) p); +} + +hb_bool_t +_hb_cairo_paint_glyph_image (hb_cairo_context_t *c, + hb_blob_t *blob, + unsigned width, + unsigned height, + hb_tag_t format, + float slant, + hb_glyph_extents_t *extents) +{ + cairo_t *cr = c->cr; + + if (!extents) /* SVG currently. */ + return false; + + cairo_surface_t *surface = nullptr; + +#ifdef CAIRO_HAS_PNG_FUNCTIONS + if (format == HB_PAINT_IMAGE_FORMAT_PNG) + { + hb_cairo_read_blob_data_t r; + r.blob = blob; + r.offset = 0; + surface = cairo_image_surface_create_from_png_stream (hb_cairo_read_blob, &r); + + /* For PNG, width,height can be unreliable, as is the case for NotoColorEmoji :(. + * Just pull them out of the surface. */ + width = cairo_image_surface_get_width (surface); + height = cairo_image_surface_get_width (surface); + } + else +#endif + if (format == HB_PAINT_IMAGE_FORMAT_BGRA) + { + /* Byte-endian conversion. */ + unsigned data_size = hb_blob_get_length (blob); + if (data_size < width * height * 4) + return false; + + unsigned char *data; +#ifdef __BYTE_ORDER + if (__BYTE_ORDER == __BIG_ENDIAN) + { + data = (unsigned char *) hb_blob_get_data_writable (blob, nullptr); + if (!data) + return false; + + unsigned count = width * height * 4; + for (unsigned i = 0; i < count; i += 4) + { + unsigned char b; + b = data[i]; + data[i] = data[i+3]; + data[i+3] = b; + b = data[i+1]; + data[i+1] = data[i+2]; + data[i+2] = b; + } + } + else +#endif + data = (unsigned char *) hb_blob_get_data (blob, nullptr); + + surface = cairo_image_surface_create_for_data (data, + CAIRO_FORMAT_ARGB32, + width, height, + width * 4); + + cairo_surface_set_user_data (surface, + _hb_cairo_surface_blob_user_data_key, + hb_blob_reference (blob), + _hb_cairo_destroy_blob); + } + + if (!surface) + return false; + + cairo_save (cr); + /* this clip is here to work around recording surface limitations */ + cairo_rectangle (cr, + extents->x_bearing, + extents->y_bearing, + extents->width, + extents->height); + cairo_clip (cr); + + cairo_pattern_t *pattern = cairo_pattern_create_for_surface (surface); + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD); + + cairo_matrix_t matrix = {(double) width, 0, 0, (double) height, 0, 0}; + cairo_pattern_set_matrix (pattern, &matrix); + + /* Undo slant in the extents and apply it in the context. */ + extents->width -= extents->height * slant; + extents->x_bearing -= extents->y_bearing * slant; + cairo_matrix_t cairo_matrix = {1., 0., (double) slant, 1., 0., 0.}; + cairo_transform (cr, &cairo_matrix); + + cairo_translate (cr, extents->x_bearing, extents->y_bearing); + cairo_scale (cr, extents->width, extents->height); + cairo_set_source (cr, pattern); + + cairo_paint (cr); + + cairo_pattern_destroy (pattern); + cairo_surface_destroy (surface); + + cairo_restore (cr); + + return true; +} + +static void +_hb_cairo_reduce_anchors (float x0, float y0, + float x1, float y1, + float x2, float y2, + float *xx0, float *yy0, + float *xx1, float *yy1) +{ + float q1x, q1y, q2x, q2y; + float s; + float k; + + q2x = x2 - x0; + q2y = y2 - y0; + q1x = x1 - x0; + q1y = y1 - y0; + + s = q2x * q2x + q2y * q2y; + if (s < 0.000001f) + { + *xx0 = x0; *yy0 = y0; + *xx1 = x1; *yy1 = y1; + return; + } + + k = (q2x * q1x + q2y * q1y) / s; + *xx0 = x0; + *yy0 = y0; + *xx1 = x1 - k * q2x; + *yy1 = y1 - k * q2y; +} + +static int +_hb_cairo_cmp_color_stop (const void *p1, + const void *p2) +{ + const hb_color_stop_t *c1 = (const hb_color_stop_t *) p1; + const hb_color_stop_t *c2 = (const hb_color_stop_t *) p2; + + if (c1->offset < c2->offset) + return -1; + else if (c1->offset > c2->offset) + return 1; + else + return 0; +} + +static void +_hb_cairo_normalize_color_line (hb_color_stop_t *stops, + unsigned int len, + float *omin, + float *omax) +{ + float min, max; + + hb_qsort (stops, len, sizeof (hb_color_stop_t), _hb_cairo_cmp_color_stop); + + min = max = stops[0].offset; + for (unsigned int i = 0; i < len; i++) + { + min = hb_min (min, stops[i].offset); + max = hb_max (max, stops[i].offset); + } + + if (min != max) + { + for (unsigned int i = 0; i < len; i++) + stops[i].offset = (stops[i].offset - min) / (max - min); + } + + *omin = min; + *omax = max; +} + +static bool +_hb_cairo_get_color_stops (hb_cairo_context_t *c, + hb_color_line_t *color_line, + unsigned *count, + hb_color_stop_t **stops) +{ + unsigned len = hb_color_line_get_color_stops (color_line, 0, nullptr, nullptr); + if (len > *count) + { + *stops = (hb_color_stop_t *) hb_malloc (len * sizeof (hb_color_stop_t)); + if (unlikely (!stops)) + return false; + } + hb_color_line_get_color_stops (color_line, 0, &len, *stops); + for (unsigned i = 0; i < len; i++) + if ((*stops)[i].is_foreground) + { +#ifdef HAVE_CAIRO_USER_SCALED_FONT_GET_FOREGROUND_SOURCE + double r, g, b, a; + cairo_pattern_t *foreground = cairo_user_scaled_font_get_foreground_source (c->scaled_font); + if (cairo_pattern_get_rgba (foreground, &r, &g, &b, &a) == CAIRO_STATUS_SUCCESS) + (*stops)[i].color = HB_COLOR (round (b * 255.), round (g * 255.), round (r * 255.), + round (a * hb_color_get_alpha ((*stops)[i].color))); + else +#endif + (*stops)[i].color = HB_COLOR (0, 0, 0, hb_color_get_alpha ((*stops)[i].color)); + } + + *count = len; + return true; +} + +void +_hb_cairo_paint_linear_gradient (hb_cairo_context_t *c, + hb_color_line_t *color_line, + float x0, float y0, + float x1, float y1, + float x2, float y2) +{ + cairo_t *cr = c->cr; + + unsigned int len = PREALLOCATED_COLOR_STOPS; + hb_color_stop_t stops_[PREALLOCATED_COLOR_STOPS]; + hb_color_stop_t *stops = stops_; + float xx0, yy0, xx1, yy1; + float xxx0, yyy0, xxx1, yyy1; + float min, max; + cairo_pattern_t *pattern; + + if (unlikely (!_hb_cairo_get_color_stops (c, color_line, &len, &stops))) + return; + _hb_cairo_normalize_color_line (stops, len, &min, &max); + + _hb_cairo_reduce_anchors (x0, y0, x1, y1, x2, y2, &xx0, &yy0, &xx1, &yy1); + + xxx0 = xx0 + min * (xx1 - xx0); + yyy0 = yy0 + min * (yy1 - yy0); + xxx1 = xx0 + max * (xx1 - xx0); + yyy1 = yy0 + max * (yy1 - yy0); + + pattern = cairo_pattern_create_linear ((double) xxx0, (double) yyy0, (double) xxx1, (double) yyy1); + cairo_pattern_set_extend (pattern, hb_cairo_extend (hb_color_line_get_extend (color_line))); + for (unsigned int i = 0; i < len; i++) + { + double r, g, b, a; + r = hb_color_get_red (stops[i].color) / 255.; + g = hb_color_get_green (stops[i].color) / 255.; + b = hb_color_get_blue (stops[i].color) / 255.; + a = hb_color_get_alpha (stops[i].color) / 255.; + cairo_pattern_add_color_stop_rgba (pattern, (double) stops[i].offset, r, g, b, a); + } + + cairo_set_source (cr, pattern); + cairo_paint (cr); + + cairo_pattern_destroy (pattern); + + if (stops != stops_) + hb_free (stops); +} + +void +_hb_cairo_paint_radial_gradient (hb_cairo_context_t *c, + hb_color_line_t *color_line, + float x0, float y0, float r0, + float x1, float y1, float r1) +{ + cairo_t *cr = c->cr; + + unsigned int len = PREALLOCATED_COLOR_STOPS; + hb_color_stop_t stops_[PREALLOCATED_COLOR_STOPS]; + hb_color_stop_t *stops = stops_; + float min, max; + float xx0, yy0, xx1, yy1; + float rr0, rr1; + cairo_pattern_t *pattern; + + if (unlikely (!_hb_cairo_get_color_stops (c, color_line, &len, &stops))) + return; + _hb_cairo_normalize_color_line (stops, len, &min, &max); + + xx0 = x0 + min * (x1 - x0); + yy0 = y0 + min * (y1 - y0); + xx1 = x0 + max * (x1 - x0); + yy1 = y0 + max * (y1 - y0); + rr0 = r0 + min * (r1 - r0); + rr1 = r0 + max * (r1 - r0); + + pattern = cairo_pattern_create_radial ((double) xx0, (double) yy0, (double) rr0, (double) xx1, (double) yy1, (double) rr1); + cairo_pattern_set_extend (pattern, hb_cairo_extend (hb_color_line_get_extend (color_line))); + + for (unsigned int i = 0; i < len; i++) + { + double r, g, b, a; + r = hb_color_get_red (stops[i].color) / 255.; + g = hb_color_get_green (stops[i].color) / 255.; + b = hb_color_get_blue (stops[i].color) / 255.; + a = hb_color_get_alpha (stops[i].color) / 255.; + cairo_pattern_add_color_stop_rgba (pattern, (double) stops[i].offset, r, g, b, a); + } + + cairo_set_source (cr, pattern); + cairo_paint (cr); + + cairo_pattern_destroy (pattern); + + if (stops != stops_) + hb_free (stops); +} + +typedef struct { + float x, y; +} hb_cairo_point_t; + +static inline float +_hb_cairo_interpolate (float f0, float f1, float f) +{ + return f0 + f * (f1 - f0); +} + +static inline void +_hb_cairo_premultiply (hb_cairo_color_t *c) +{ + c->r *= c->a; + c->g *= c->a; + c->b *= c->a; +} + +static inline void +_hb_cairo_unpremultiply (hb_cairo_color_t *c) +{ + if (c->a != 0.f) + { + c->r /= c->a; + c->g /= c->a; + c->b /= c->a; + } +} + +static void +_hb_cairo_interpolate_colors (hb_cairo_color_t *c0, hb_cairo_color_t *c1, float k, hb_cairo_color_t *c) +{ + // According to the COLR specification, gradients + // should be interpolated in premultiplied form + _hb_cairo_premultiply (c0); + _hb_cairo_premultiply (c1); + c->r = c0->r + k * (c1->r - c0->r); + c->g = c0->g + k * (c1->g - c0->g); + c->b = c0->b + k * (c1->b - c0->b); + c->a = c0->a + k * (c1->a - c0->a); + _hb_cairo_unpremultiply (c); +} + +static inline float +_hb_cairo_dot (hb_cairo_point_t p, hb_cairo_point_t q) +{ + return p.x * q.x + p.y * q.y; +} + +static inline hb_cairo_point_t +_hb_cairo_normalize (hb_cairo_point_t p) +{ + float len = sqrtf (_hb_cairo_dot (p, p)); + + return hb_cairo_point_t { p.x / len, p.y / len }; +} + +static inline hb_cairo_point_t +_hb_cairo_sum (hb_cairo_point_t p, hb_cairo_point_t q) +{ + return hb_cairo_point_t { p.x + q.x, p.y + q.y }; +} + +static inline hb_cairo_point_t +_hb_cairo_difference (hb_cairo_point_t p, hb_cairo_point_t q) +{ + return hb_cairo_point_t { p.x - q.x, p.y - q.y }; +} + +static inline hb_cairo_point_t +_hb_cairo_scale (hb_cairo_point_t p, float f) +{ + return hb_cairo_point_t { p.x * f, p.y * f }; +} + +typedef struct { + hb_cairo_point_t center, p0, c0, c1, p1; + hb_cairo_color_t color0, color1; +} hb_cairo_patch_t; + +static void +_hb_cairo_add_patch (cairo_pattern_t *pattern, hb_cairo_point_t *center, hb_cairo_patch_t *p) +{ + cairo_mesh_pattern_begin_patch (pattern); + cairo_mesh_pattern_move_to (pattern, (double) center->x, (double) center->y); + cairo_mesh_pattern_line_to (pattern, (double) p->p0.x, (double) p->p0.y); + cairo_mesh_pattern_curve_to (pattern, + (double) p->c0.x, (double) p->c0.y, + (double) p->c1.x, (double) p->c1.y, + (double) p->p1.x, (double) p->p1.y); + cairo_mesh_pattern_line_to (pattern, (double) center->x, (double) center->y); + cairo_mesh_pattern_set_corner_color_rgba (pattern, 0, + (double) p->color0.r, + (double) p->color0.g, + (double) p->color0.b, + (double) p->color0.a); + cairo_mesh_pattern_set_corner_color_rgba (pattern, 1, + (double) p->color0.r, + (double) p->color0.g, + (double) p->color0.b, + (double) p->color0.a); + cairo_mesh_pattern_set_corner_color_rgba (pattern, 2, + (double) p->color1.r, + (double) p->color1.g, + (double) p->color1.b, + (double) p->color1.a); + cairo_mesh_pattern_set_corner_color_rgba (pattern, 3, + (double) p->color1.r, + (double) p->color1.g, + (double) p->color1.b, + (double) p->color1.a); + cairo_mesh_pattern_end_patch (pattern); +} + +#define MAX_ANGLE (HB_PI / 8.f) + +static void +_hb_cairo_add_sweep_gradient_patches1 (float cx, float cy, float radius, + float a0, hb_cairo_color_t *c0, + float a1, hb_cairo_color_t *c1, + cairo_pattern_t *pattern) +{ + hb_cairo_point_t center = hb_cairo_point_t { cx, cy }; + int num_splits; + hb_cairo_point_t p0; + hb_cairo_color_t color0, color1; + + num_splits = ceilf (fabsf (a1 - a0) / MAX_ANGLE); + p0 = hb_cairo_point_t { cosf (a0), sinf (a0) }; + color0 = *c0; + + for (int a = 0; a < num_splits; a++) + { + float k = (a + 1.) / num_splits; + float angle1; + hb_cairo_point_t p1; + hb_cairo_point_t A, U; + hb_cairo_point_t C0, C1; + hb_cairo_patch_t patch; + + angle1 = _hb_cairo_interpolate (a0, a1, k); + _hb_cairo_interpolate_colors (c0, c1, k, &color1); + + patch.color0 = color0; + patch.color1 = color1; + + p1 = hb_cairo_point_t { cosf (angle1), sinf (angle1) }; + patch.p0 = _hb_cairo_sum (center, _hb_cairo_scale (p0, radius)); + patch.p1 = _hb_cairo_sum (center, _hb_cairo_scale (p1, radius)); + + A = _hb_cairo_normalize (_hb_cairo_sum (p0, p1)); + U = hb_cairo_point_t { -A.y, A.x }; + C0 = _hb_cairo_sum (A, _hb_cairo_scale (U, _hb_cairo_dot (_hb_cairo_difference (p0, A), p0) / _hb_cairo_dot (U, p0))); + C1 = _hb_cairo_sum (A, _hb_cairo_scale (U, _hb_cairo_dot (_hb_cairo_difference (p1, A), p1) / _hb_cairo_dot (U, p1))); + + patch.c0 = _hb_cairo_sum (center, _hb_cairo_scale (_hb_cairo_sum (C0, _hb_cairo_scale (_hb_cairo_difference (C0, p0), 0.33333f)), radius)); + patch.c1 = _hb_cairo_sum (center, _hb_cairo_scale (_hb_cairo_sum (C1, _hb_cairo_scale (_hb_cairo_difference (C1, p1), 0.33333f)), radius)); + + _hb_cairo_add_patch (pattern, ¢er, &patch); + + p0 = p1; + color0 = color1; + } +} + +static void +_hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops, + unsigned int n_stops, + cairo_extend_t extend, + float cx, float cy, + float radius, + float start_angle, + float end_angle, + cairo_pattern_t *pattern) +{ + float angles_[PREALLOCATED_COLOR_STOPS]; + float *angles = angles_; + hb_cairo_color_t colors_[PREALLOCATED_COLOR_STOPS]; + hb_cairo_color_t *colors = colors_; + hb_cairo_color_t color0, color1; + + if (start_angle == end_angle) + { + if (extend == CAIRO_EXTEND_PAD) + { + hb_cairo_color_t c; + if (start_angle > 0) + { + c.r = hb_color_get_red (stops[0].color) / 255.; + c.g = hb_color_get_green (stops[0].color) / 255.; + c.b = hb_color_get_blue (stops[0].color) / 255.; + c.a = hb_color_get_alpha (stops[0].color) / 255.; + _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, + 0., &c, + start_angle, &c, + pattern); + } + if (end_angle < HB_2_PI) + { + c.r = hb_color_get_red (stops[n_stops - 1].color) / 255.; + c.g = hb_color_get_green (stops[n_stops - 1].color) / 255.; + c.b = hb_color_get_blue (stops[n_stops - 1].color) / 255.; + c.a = hb_color_get_alpha (stops[n_stops - 1].color) / 255.; + _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, + end_angle, &c, + HB_2_PI, &c, + pattern); + } + } + return; + } + + assert (start_angle != end_angle); + + /* handle directions */ + if (end_angle < start_angle) + { + hb_swap (start_angle, end_angle); + + for (unsigned i = 0; i < n_stops - 1 - i; i++) + hb_swap (stops[i], stops[n_stops - 1 - i]); + for (unsigned i = 0; i < n_stops; i++) + stops[i].offset = 1 - stops[i].offset; + } + + if (n_stops > PREALLOCATED_COLOR_STOPS) + { + angles = (float *) hb_malloc (sizeof (float) * n_stops); + colors = (hb_cairo_color_t *) hb_malloc (sizeof (hb_cairo_color_t) * n_stops); + if (unlikely (!angles || !colors)) + { + hb_free (angles); + hb_free (colors); + return; + } + } + + for (unsigned i = 0; i < n_stops; i++) + { + angles[i] = start_angle + stops[i].offset * (end_angle - start_angle); + colors[i].r = hb_color_get_red (stops[i].color) / 255.; + colors[i].g = hb_color_get_green (stops[i].color) / 255.; + colors[i].b = hb_color_get_blue (stops[i].color) / 255.; + colors[i].a = hb_color_get_alpha (stops[i].color) / 255.; + } + + if (extend == CAIRO_EXTEND_PAD) + { + unsigned pos; + + color0 = colors[0]; + for (pos = 0; pos < n_stops; pos++) + { + if (angles[pos] >= 0) + { + if (pos > 0) + { + float k = (0 - angles[pos - 1]) / (angles[pos] - angles[pos - 1]); + _hb_cairo_interpolate_colors (&colors[pos-1], &colors[pos], k, &color0); + } + break; + } + } + if (pos == n_stops) + { + /* everything is below 0 */ + color0 = colors[n_stops-1]; + _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, + 0., &color0, + HB_2_PI, &color0, + pattern); + goto done; + } + + _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, + 0., &color0, + angles[pos], &colors[pos], + pattern); + + for (pos++; pos < n_stops; pos++) + { + if (angles[pos] <= HB_2_PI) + { + _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, + angles[pos - 1], &colors[pos-1], + angles[pos], &colors[pos], + pattern); + } + else + { + float k = (HB_2_PI - angles[pos - 1]) / (angles[pos] - angles[pos - 1]); + _hb_cairo_interpolate_colors (&colors[pos - 1], &colors[pos], k, &color1); + _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, + angles[pos - 1], &colors[pos - 1], + HB_2_PI, &color1, + pattern); + break; + } + } + + if (pos == n_stops) + { + /* everything is below 2*M_PI */ + color0 = colors[n_stops - 1]; + _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, + angles[n_stops - 1], &color0, + HB_2_PI, &color0, + pattern); + goto done; + } + } + else + { + int k; + float span; + + span = angles[n_stops - 1] - angles[0]; + k = 0; + if (angles[0] >= 0) + { + float ss = angles[0]; + while (ss > 0) + { + if (span > 0) + { + ss -= span; + k--; + } + else + { + ss += span; + k++; + } + } + } + else if (angles[0] < 0) + { + float ee = angles[n_stops - 1]; + while (ee < 0) + { + if (span > 0) + { + ee += span; + k++; + } + else + { + ee -= span; + k--; + } + } + } + + //assert (angles[0] + k * span <= 0 && 0 < angles[n_stops - 1] + k * span); + span = fabsf (span); + + for (signed l = k; l < 1000; l++) + { + for (unsigned i = 1; i < n_stops; i++) + { + float a0, a1; + hb_cairo_color_t *c0, *c1; + + if ((l % 2 != 0) && (extend == CAIRO_EXTEND_REFLECT)) + { + a0 = angles[0] + angles[n_stops - 1] - angles[n_stops - 1 - (i-1)] + l * span; + a1 = angles[0] + angles[n_stops - 1] - angles[n_stops - 1 - i] + l * span; + c0 = &colors[n_stops - 1 - (i - 1)]; + c1 = &colors[n_stops - 1 - i]; + } + else + { + a0 = angles[i-1] + l * span; + a1 = angles[i] + l * span; + c0 = &colors[i-1]; + c1 = &colors[i]; + } + + if (a1 < 0) + continue; + if (a0 < 0) + { + hb_cairo_color_t color; + float f = (0 - a0)/(a1 - a0); + _hb_cairo_interpolate_colors (c0, c1, f, &color); + _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, + 0, &color, + a1, c1, + pattern); + } + else if (a1 >= HB_2_PI) + { + hb_cairo_color_t color; + float f = (HB_2_PI - a0)/(a1 - a0); + _hb_cairo_interpolate_colors (c0, c1, f, &color); + _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, + a0, c0, + HB_2_PI, &color, + pattern); + goto done; + } + else + { + _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, + a0, c0, + a1, c1, + pattern); + } + } + } + } + +done: + + if (angles != angles_) + hb_free (angles); + if (colors != colors_) + hb_free (colors); +} + +void +_hb_cairo_paint_sweep_gradient (hb_cairo_context_t *c, + hb_color_line_t *color_line, + float cx, float cy, + float start_angle, + float end_angle) +{ + cairo_t *cr = c->cr; + + unsigned int len = PREALLOCATED_COLOR_STOPS; + hb_color_stop_t stops_[PREALLOCATED_COLOR_STOPS]; + hb_color_stop_t *stops = stops_; + cairo_extend_t extend; + double x1, y1, x2, y2; + float max_x, max_y, radius; + cairo_pattern_t *pattern; + + if (unlikely (!_hb_cairo_get_color_stops (c, color_line, &len, &stops))) + return; + + hb_qsort (stops, len, sizeof (hb_color_stop_t), _hb_cairo_cmp_color_stop); + + cairo_clip_extents (cr, &x1, &y1, &x2, &y2); + max_x = (float) hb_max ((x1 - (double) cx) * (x1 - (double) cx), (x2 - (double) cx) * (x2 - (double) cx)); + max_y = (float) hb_max ((y1 - (double) cy) * (y1 - (double) cy), (y2 - (double) cy) * (y2 - (double) cy)); + radius = sqrtf (max_x + max_y); + + extend = hb_cairo_extend (hb_color_line_get_extend (color_line)); + pattern = cairo_pattern_create_mesh (); + + _hb_cairo_add_sweep_gradient_patches (stops, len, extend, cx, cy, + radius, start_angle, end_angle, pattern); + + cairo_set_source (cr, pattern); + cairo_paint (cr); + + cairo_pattern_destroy (pattern); + + if (stops != stops_) + hb_free (stops); +} + +#endif diff --git a/libs/harfbuzz/src/hb-cairo-utils.hh b/libs/harfbuzz/src/hb-cairo-utils.hh new file mode 100644 index 000000000..a26bf59d9 --- /dev/null +++ b/libs/harfbuzz/src/hb-cairo-utils.hh @@ -0,0 +1,107 @@ +/* + * Copyright © 2022 Red Hat, Inc + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Matthias Clasen + */ + +#ifndef HB_CAIRO_UTILS_H +#define HB_CAIRO_UTILS_H + +#include "hb.hh" +#include "hb-cairo.h" + + +typedef struct +{ + cairo_scaled_font_t *scaled_font; + cairo_t *cr; + hb_map_t *color_cache; +} hb_cairo_context_t; + +static inline cairo_operator_t +_hb_paint_composite_mode_to_cairo (hb_paint_composite_mode_t mode) +{ + switch (mode) + { + case HB_PAINT_COMPOSITE_MODE_CLEAR: return CAIRO_OPERATOR_CLEAR; + case HB_PAINT_COMPOSITE_MODE_SRC: return CAIRO_OPERATOR_SOURCE; + case HB_PAINT_COMPOSITE_MODE_DEST: return CAIRO_OPERATOR_DEST; + case HB_PAINT_COMPOSITE_MODE_SRC_OVER: return CAIRO_OPERATOR_OVER; + case HB_PAINT_COMPOSITE_MODE_DEST_OVER: return CAIRO_OPERATOR_DEST_OVER; + case HB_PAINT_COMPOSITE_MODE_SRC_IN: return CAIRO_OPERATOR_IN; + case HB_PAINT_COMPOSITE_MODE_DEST_IN: return CAIRO_OPERATOR_DEST_IN; + case HB_PAINT_COMPOSITE_MODE_SRC_OUT: return CAIRO_OPERATOR_OUT; + case HB_PAINT_COMPOSITE_MODE_DEST_OUT: return CAIRO_OPERATOR_DEST_OUT; + case HB_PAINT_COMPOSITE_MODE_SRC_ATOP: return CAIRO_OPERATOR_ATOP; + case HB_PAINT_COMPOSITE_MODE_DEST_ATOP: return CAIRO_OPERATOR_DEST_ATOP; + case HB_PAINT_COMPOSITE_MODE_XOR: return CAIRO_OPERATOR_XOR; + case HB_PAINT_COMPOSITE_MODE_PLUS: return CAIRO_OPERATOR_ADD; + case HB_PAINT_COMPOSITE_MODE_SCREEN: return CAIRO_OPERATOR_SCREEN; + case HB_PAINT_COMPOSITE_MODE_OVERLAY: return CAIRO_OPERATOR_OVERLAY; + case HB_PAINT_COMPOSITE_MODE_DARKEN: return CAIRO_OPERATOR_DARKEN; + case HB_PAINT_COMPOSITE_MODE_LIGHTEN: return CAIRO_OPERATOR_LIGHTEN; + case HB_PAINT_COMPOSITE_MODE_COLOR_DODGE: return CAIRO_OPERATOR_COLOR_DODGE; + case HB_PAINT_COMPOSITE_MODE_COLOR_BURN: return CAIRO_OPERATOR_COLOR_BURN; + case HB_PAINT_COMPOSITE_MODE_HARD_LIGHT: return CAIRO_OPERATOR_HARD_LIGHT; + case HB_PAINT_COMPOSITE_MODE_SOFT_LIGHT: return CAIRO_OPERATOR_SOFT_LIGHT; + case HB_PAINT_COMPOSITE_MODE_DIFFERENCE: return CAIRO_OPERATOR_DIFFERENCE; + case HB_PAINT_COMPOSITE_MODE_EXCLUSION: return CAIRO_OPERATOR_EXCLUSION; + case HB_PAINT_COMPOSITE_MODE_MULTIPLY: return CAIRO_OPERATOR_MULTIPLY; + case HB_PAINT_COMPOSITE_MODE_HSL_HUE: return CAIRO_OPERATOR_HSL_HUE; + case HB_PAINT_COMPOSITE_MODE_HSL_SATURATION: return CAIRO_OPERATOR_HSL_SATURATION; + case HB_PAINT_COMPOSITE_MODE_HSL_COLOR: return CAIRO_OPERATOR_HSL_COLOR; + case HB_PAINT_COMPOSITE_MODE_HSL_LUMINOSITY: return CAIRO_OPERATOR_HSL_LUMINOSITY; + default: return CAIRO_OPERATOR_CLEAR; + } +} + +HB_INTERNAL hb_bool_t +_hb_cairo_paint_glyph_image (hb_cairo_context_t *c, + hb_blob_t *blob, + unsigned width, + unsigned height, + hb_tag_t format, + float slant, + hb_glyph_extents_t *extents); + +HB_INTERNAL void +_hb_cairo_paint_linear_gradient (hb_cairo_context_t *c, + hb_color_line_t *color_line, + float x0, float y0, + float x1, float y1, + float x2, float y2); + +HB_INTERNAL void +_hb_cairo_paint_radial_gradient (hb_cairo_context_t *c, + hb_color_line_t *color_line, + float x0, float y0, float r0, + float x1, float y1, float r1); + +HB_INTERNAL void +_hb_cairo_paint_sweep_gradient (hb_cairo_context_t *c, + hb_color_line_t *color_line, + float x0, float y0, + float start_angle, float end_angle); + + +#endif /* HB_CAIRO_UTILS_H */ diff --git a/libs/harfbuzz/src/hb-cairo.cc b/libs/harfbuzz/src/hb-cairo.cc new file mode 100644 index 000000000..d8b582c49 --- /dev/null +++ b/libs/harfbuzz/src/hb-cairo.cc @@ -0,0 +1,1037 @@ +/* + * Copyright © 2022 Red Hat, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Matthias Clasen + */ + +#include "hb.hh" + +#ifdef HAVE_CAIRO + +#include "hb-cairo.h" + +#include "hb-cairo-utils.hh" + +#include "hb-machinery.hh" +#include "hb-utf.hh" + + +/** + * SECTION:hb-cairo + * @title: hb-cairo + * @short_description: Cairo integration + * @include: hb-cairo.h + * + * Functions for using HarfBuzz with the cairo library. + * + * HarfBuzz supports using cairo for rendering. + **/ + +static void +hb_cairo_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED, + void *draw_data, + hb_draw_state_t *st HB_UNUSED, + float to_x, float to_y, + void *user_data HB_UNUSED) +{ + cairo_t *cr = (cairo_t *) draw_data; + + cairo_move_to (cr, (double) to_x, (double) to_y); +} + +static void +hb_cairo_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED, + void *draw_data, + hb_draw_state_t *st HB_UNUSED, + float to_x, float to_y, + void *user_data HB_UNUSED) +{ + cairo_t *cr = (cairo_t *) draw_data; + + cairo_line_to (cr, (double) to_x, (double) to_y); +} + +static void +hb_cairo_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED, + void *draw_data, + hb_draw_state_t *st HB_UNUSED, + float control1_x, float control1_y, + float control2_x, float control2_y, + float to_x, float to_y, + void *user_data HB_UNUSED) +{ + cairo_t *cr = (cairo_t *) draw_data; + + cairo_curve_to (cr, + (double) control1_x, (double) control1_y, + (double) control2_x, (double) control2_y, + (double) to_x, (double) to_y); +} + +static void +hb_cairo_close_path (hb_draw_funcs_t *dfuncs HB_UNUSED, + void *draw_data, + hb_draw_state_t *st HB_UNUSED, + void *user_data HB_UNUSED) +{ + cairo_t *cr = (cairo_t *) draw_data; + + cairo_close_path (cr); +} + +static inline void free_static_cairo_draw_funcs (); + +static struct hb_cairo_draw_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t +{ + static hb_draw_funcs_t *create () + { + hb_draw_funcs_t *funcs = hb_draw_funcs_create (); + + hb_draw_funcs_set_move_to_func (funcs, hb_cairo_move_to, nullptr, nullptr); + hb_draw_funcs_set_line_to_func (funcs, hb_cairo_line_to, nullptr, nullptr); + hb_draw_funcs_set_cubic_to_func (funcs, hb_cairo_cubic_to, nullptr, nullptr); + hb_draw_funcs_set_close_path_func (funcs, hb_cairo_close_path, nullptr, nullptr); + + hb_draw_funcs_make_immutable (funcs); + + hb_atexit (free_static_cairo_draw_funcs); + + return funcs; + } +} static_cairo_draw_funcs; + +static inline +void free_static_cairo_draw_funcs () +{ + static_cairo_draw_funcs.free_instance (); +} + +static hb_draw_funcs_t * +hb_cairo_draw_get_funcs () +{ + return static_cairo_draw_funcs.get_unconst (); +} + + +#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC + +static void +hb_cairo_push_transform (hb_paint_funcs_t *pfuncs HB_UNUSED, + void *paint_data, + float xx, float yx, + float xy, float yy, + float dx, float dy, + void *user_data HB_UNUSED) +{ + hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data; + cairo_t *cr = c->cr; + + cairo_matrix_t m; + + cairo_save (cr); + cairo_matrix_init (&m, (double) xx, (double) yx, + (double) xy, (double) yy, + (double) dx, (double) dy); + cairo_transform (cr, &m); +} + +static void +hb_cairo_pop_transform (hb_paint_funcs_t *pfuncs HB_UNUSED, + void *paint_data, + void *user_data HB_UNUSED) +{ + hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data; + cairo_t *cr = c->cr; + + cairo_restore (cr); +} + +static hb_bool_t +hb_cairo_paint_color_glyph (hb_paint_funcs_t *pfuncs HB_UNUSED, + void *paint_data, + hb_codepoint_t glyph, + hb_font_t *font, + void *user_data HB_UNUSED) +{ + hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data; + cairo_t *cr = c->cr; + + cairo_save (cr); + + hb_position_t x_scale, y_scale; + hb_font_get_scale (font, &x_scale, &y_scale); + cairo_scale (cr, x_scale, y_scale); + + cairo_glyph_t cairo_glyph = { glyph, 0, 0 }; + cairo_set_scaled_font (cr, c->scaled_font); + cairo_set_font_size (cr, 1); + cairo_show_glyphs (cr, &cairo_glyph, 1); + + cairo_restore (cr); + + return true; +} + +static void +hb_cairo_push_clip_glyph (hb_paint_funcs_t *pfuncs HB_UNUSED, + void *paint_data, + hb_codepoint_t glyph, + hb_font_t *font, + void *user_data HB_UNUSED) +{ + hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data; + cairo_t *cr = c->cr; + + cairo_save (cr); + cairo_new_path (cr); + hb_font_draw_glyph (font, glyph, hb_cairo_draw_get_funcs (), cr); + cairo_close_path (cr); + cairo_clip (cr); +} + +static void +hb_cairo_push_clip_rectangle (hb_paint_funcs_t *pfuncs HB_UNUSED, + void *paint_data, + float xmin, float ymin, float xmax, float ymax, + void *user_data HB_UNUSED) +{ + hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data; + cairo_t *cr = c->cr; + + cairo_save (cr); + cairo_rectangle (cr, + (double) xmin, (double) ymin, + (double) (xmax - xmin), (double) (ymax - ymin)); + cairo_clip (cr); +} + +static void +hb_cairo_pop_clip (hb_paint_funcs_t *pfuncs HB_UNUSED, + void *paint_data, + void *user_data HB_UNUSED) +{ + hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data; + cairo_t *cr = c->cr; + + cairo_restore (cr); +} + +static void +hb_cairo_push_group (hb_paint_funcs_t *pfuncs HB_UNUSED, + void *paint_data, + void *user_data HB_UNUSED) +{ + hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data; + cairo_t *cr = c->cr; + + cairo_save (cr); + cairo_push_group (cr); +} + +static void +hb_cairo_pop_group (hb_paint_funcs_t *pfuncs HB_UNUSED, + void *paint_data, + hb_paint_composite_mode_t mode, + void *user_data HB_UNUSED) +{ + hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data; + cairo_t *cr = c->cr; + + cairo_pop_group_to_source (cr); + cairo_set_operator (cr, _hb_paint_composite_mode_to_cairo (mode)); + cairo_paint (cr); + + cairo_restore (cr); +} + +static void +hb_cairo_paint_color (hb_paint_funcs_t *pfuncs HB_UNUSED, + void *paint_data, + hb_bool_t use_foreground, + hb_color_t color, + void *user_data HB_UNUSED) +{ + hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data; + cairo_t *cr = c->cr; + + if (use_foreground) + { +#ifdef HAVE_CAIRO_USER_SCALED_FONT_GET_FOREGROUND_SOURCE + double r, g, b, a; + cairo_pattern_t *foreground = cairo_user_scaled_font_get_foreground_source (c->scaled_font); + if (cairo_pattern_get_rgba (foreground, &r, &g, &b, &a) == CAIRO_STATUS_SUCCESS) + cairo_set_source_rgba (cr, r, g, b, a * hb_color_get_alpha (color) / 255.); + else +#endif + cairo_set_source_rgba (cr, 0, 0, 0, hb_color_get_alpha (color) / 255.); + } + else + cairo_set_source_rgba (cr, + hb_color_get_red (color) / 255., + hb_color_get_green (color) / 255., + hb_color_get_blue (color) / 255., + hb_color_get_alpha (color) / 255.); + cairo_paint (cr); +} + +static hb_bool_t +hb_cairo_paint_image (hb_paint_funcs_t *pfuncs HB_UNUSED, + void *paint_data, + hb_blob_t *blob, + unsigned width, + unsigned height, + hb_tag_t format, + float slant, + hb_glyph_extents_t *extents, + void *user_data HB_UNUSED) +{ + hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data; + + return _hb_cairo_paint_glyph_image (c, blob, width, height, format, slant, extents); +} + +static void +hb_cairo_paint_linear_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, + void *paint_data, + hb_color_line_t *color_line, + float x0, float y0, + float x1, float y1, + float x2, float y2, + void *user_data HB_UNUSED) +{ + hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data; + + _hb_cairo_paint_linear_gradient (c, color_line, x0, y0, x1, y1, x2, y2); +} + +static void +hb_cairo_paint_radial_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, + void *paint_data, + hb_color_line_t *color_line, + float x0, float y0, float r0, + float x1, float y1, float r1, + void *user_data HB_UNUSED) +{ + hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data; + + _hb_cairo_paint_radial_gradient (c, color_line, x0, y0, r0, x1, y1, r1); +} + +static void +hb_cairo_paint_sweep_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, + void *paint_data, + hb_color_line_t *color_line, + float x0, float y0, + float start_angle, float end_angle, + void *user_data HB_UNUSED) +{ + hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data; + + _hb_cairo_paint_sweep_gradient (c, color_line, x0, y0, start_angle, end_angle); +} + +static const cairo_user_data_key_t color_cache_key = {0}; + +static void +_hb_cairo_destroy_map (void *p) +{ + hb_map_destroy ((hb_map_t *) p); +} + +static hb_bool_t +hb_cairo_paint_custom_palette_color (hb_paint_funcs_t *funcs, + void *paint_data, + unsigned int color_index, + hb_color_t *color, + void *user_data HB_UNUSED) +{ +#ifdef HAVE_CAIRO_FONT_OPTIONS_GET_CUSTOM_PALETTE_COLOR + hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data; + cairo_t *cr = c->cr; + +#define HB_DEADBEEF HB_TAG(0xDE,0xAD,0xBE,0xEF) + + hb_map_t *color_cache = c->color_cache; + hb_codepoint_t *v; + if (likely (color_cache && color_cache->has (color_index, &v))) + { + if (*v == HB_DEADBEEF) + return false; + *color = *v; + return true; + } + + cairo_font_options_t *options; + double red, green, blue, alpha; + + options = cairo_font_options_create (); + cairo_get_font_options (cr, options); + if (CAIRO_STATUS_SUCCESS == + cairo_font_options_get_custom_palette_color (options, color_index, + &red, &green, &blue, &alpha)) + { + cairo_font_options_destroy (options); + *color = HB_COLOR (round (255 * blue), + round (255 * green), + round (255 * red), + round (255 * alpha)); + + if (likely (color_cache && *color != HB_DEADBEEF)) + color_cache->set (color_index, *color); + + return true; + } + cairo_font_options_destroy (options); + + if (likely (color_cache)) + color_cache->set (color_index, HB_DEADBEEF); + +#undef HB_DEADBEEF + +#endif + + return false; +} + +static inline void free_static_cairo_paint_funcs (); + +static struct hb_cairo_paint_funcs_lazy_loader_t : hb_paint_funcs_lazy_loader_t +{ + static hb_paint_funcs_t *create () + { + hb_paint_funcs_t *funcs = hb_paint_funcs_create (); + + hb_paint_funcs_set_push_transform_func (funcs, hb_cairo_push_transform, nullptr, nullptr); + hb_paint_funcs_set_pop_transform_func (funcs, hb_cairo_pop_transform, nullptr, nullptr); + hb_paint_funcs_set_color_glyph_func (funcs, hb_cairo_paint_color_glyph, nullptr, nullptr); + hb_paint_funcs_set_push_clip_glyph_func (funcs, hb_cairo_push_clip_glyph, nullptr, nullptr); + hb_paint_funcs_set_push_clip_rectangle_func (funcs, hb_cairo_push_clip_rectangle, nullptr, nullptr); + hb_paint_funcs_set_pop_clip_func (funcs, hb_cairo_pop_clip, nullptr, nullptr); + hb_paint_funcs_set_push_group_func (funcs, hb_cairo_push_group, nullptr, nullptr); + hb_paint_funcs_set_pop_group_func (funcs, hb_cairo_pop_group, nullptr, nullptr); + hb_paint_funcs_set_color_func (funcs, hb_cairo_paint_color, nullptr, nullptr); + hb_paint_funcs_set_image_func (funcs, hb_cairo_paint_image, nullptr, nullptr); + hb_paint_funcs_set_linear_gradient_func (funcs, hb_cairo_paint_linear_gradient, nullptr, nullptr); + hb_paint_funcs_set_radial_gradient_func (funcs, hb_cairo_paint_radial_gradient, nullptr, nullptr); + hb_paint_funcs_set_sweep_gradient_func (funcs, hb_cairo_paint_sweep_gradient, nullptr, nullptr); + hb_paint_funcs_set_custom_palette_color_func (funcs, hb_cairo_paint_custom_palette_color, nullptr, nullptr); + + hb_paint_funcs_make_immutable (funcs); + + hb_atexit (free_static_cairo_paint_funcs); + + return funcs; + } +} static_cairo_paint_funcs; + +static inline +void free_static_cairo_paint_funcs () +{ + static_cairo_paint_funcs.free_instance (); +} + +static hb_paint_funcs_t * +hb_cairo_paint_get_funcs () +{ + return static_cairo_paint_funcs.get_unconst (); +} +#endif + +static const cairo_user_data_key_t hb_cairo_face_user_data_key = {0}; +static const cairo_user_data_key_t hb_cairo_font_user_data_key = {0}; +static const cairo_user_data_key_t hb_cairo_font_init_func_user_data_key = {0}; +static const cairo_user_data_key_t hb_cairo_font_init_user_data_user_data_key = {0}; +static const cairo_user_data_key_t hb_cairo_scale_factor_user_data_key = {0}; + +static void hb_cairo_face_destroy (void *p) { hb_face_destroy ((hb_face_t *) p); } +static void hb_cairo_font_destroy (void *p) { hb_font_destroy ((hb_font_t *) p); } + +static cairo_status_t +hb_cairo_init_scaled_font (cairo_scaled_font_t *scaled_font, + cairo_t *cr HB_UNUSED, + cairo_font_extents_t *extents) +{ + cairo_font_face_t *font_face = cairo_scaled_font_get_font_face (scaled_font); + + hb_font_t *font = (hb_font_t *) cairo_font_face_get_user_data (font_face, + &hb_cairo_font_user_data_key); + + if (!font) + { + hb_face_t *face = (hb_face_t *) cairo_font_face_get_user_data (font_face, + &hb_cairo_face_user_data_key); + font = hb_font_create (face); + +#if !defined(HB_NO_VAR) && CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,16,0) + cairo_font_options_t *font_options = cairo_font_options_create (); + + // Set variations + cairo_scaled_font_get_font_options (scaled_font, font_options); + const char *variations = cairo_font_options_get_variations (font_options); + hb_vector_t vars; + const char *p = variations; + while (p && *p) + { + const char *end = strpbrk ((char *) p, ", "); + hb_variation_t var; + if (hb_variation_from_string (p, end ? end - p : -1, &var)) + vars.push (var); + p = end ? end + 1 : nullptr; + } + hb_font_set_variations (font, &vars[0], vars.length); + + cairo_font_options_destroy (font_options); +#endif + + // Set scale; Note: should NOT set slant, or we'll double-slant. + unsigned scale_factor = hb_cairo_font_face_get_scale_factor (font_face); + if (scale_factor) + { + cairo_matrix_t font_matrix; + cairo_scaled_font_get_scale_matrix (scaled_font, &font_matrix); + hb_font_set_scale (font, + round (font_matrix.xx * scale_factor), + round (font_matrix.yy * scale_factor)); + } + + auto *init_func = (hb_cairo_font_init_func_t) + cairo_font_face_get_user_data (font_face, + &hb_cairo_font_init_func_user_data_key); + if (init_func) + { + void *user_data = cairo_font_face_get_user_data (font_face, + &hb_cairo_font_init_user_data_user_data_key); + font = init_func (font, scaled_font, user_data); + } + + hb_font_make_immutable (font); + } + + cairo_scaled_font_set_user_data (scaled_font, + &hb_cairo_font_user_data_key, + (void *) hb_font_reference (font), + hb_cairo_font_destroy); + + hb_position_t x_scale, y_scale; + hb_font_get_scale (font, &x_scale, &y_scale); + + hb_font_extents_t hb_extents; + hb_font_get_h_extents (font, &hb_extents); + + extents->ascent = (double) hb_extents.ascender / y_scale; + extents->descent = (double) -hb_extents.descender / y_scale; + extents->height = extents->ascent + extents->descent; + +#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC + hb_map_t *color_cache = hb_map_create (); + if (unlikely (CAIRO_STATUS_SUCCESS != cairo_scaled_font_set_user_data (scaled_font, + &color_cache_key, + color_cache, + _hb_cairo_destroy_map))) + hb_map_destroy (color_cache); +#endif + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +hb_cairo_text_to_glyphs (cairo_scaled_font_t *scaled_font, + const char *utf8, + int utf8_len, + cairo_glyph_t **glyphs, + int *num_glyphs, + cairo_text_cluster_t **clusters, + int *num_clusters, + cairo_text_cluster_flags_t *cluster_flags) +{ + hb_font_t *font = (hb_font_t *) cairo_scaled_font_get_user_data (scaled_font, + &hb_cairo_font_user_data_key); + + hb_buffer_t *buffer = hb_buffer_create (); + hb_buffer_add_utf8 (buffer, utf8, utf8_len, 0, utf8_len); + hb_buffer_guess_segment_properties (buffer); + hb_shape (font, buffer, nullptr, 0); + + hb_cairo_glyphs_from_buffer (buffer, + true, + font->x_scale, font->y_scale, + 0., 0., + utf8, utf8_len, + glyphs, (unsigned *) num_glyphs, + clusters, (unsigned *) num_clusters, + cluster_flags); + + hb_buffer_destroy (buffer); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +hb_cairo_render_glyph (cairo_scaled_font_t *scaled_font, + unsigned long glyph, + cairo_t *cr, + cairo_text_extents_t *extents) +{ + hb_font_t *font = (hb_font_t *) cairo_scaled_font_get_user_data (scaled_font, + &hb_cairo_font_user_data_key); + + hb_position_t x_scale, y_scale; + hb_font_get_scale (font, &x_scale, &y_scale); + cairo_scale (cr, +1./x_scale, -1./y_scale); + + hb_font_draw_glyph (font, glyph, hb_cairo_draw_get_funcs (), cr); + + cairo_fill (cr); + + return CAIRO_STATUS_SUCCESS; +} + +#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC + +static cairo_status_t +hb_cairo_render_color_glyph (cairo_scaled_font_t *scaled_font, + unsigned long glyph, + cairo_t *cr, + cairo_text_extents_t *extents) +{ + hb_font_t *font = (hb_font_t *) cairo_scaled_font_get_user_data (scaled_font, + &hb_cairo_font_user_data_key); + + unsigned int palette = 0; +#ifdef CAIRO_COLOR_PALETTE_DEFAULT + cairo_font_options_t *options = cairo_font_options_create (); + cairo_scaled_font_get_font_options (scaled_font, options); + palette = cairo_font_options_get_color_palette (options); + cairo_font_options_destroy (options); +#endif + + hb_color_t color = HB_COLOR (0, 0, 0, 255); + hb_position_t x_scale, y_scale; + hb_font_get_scale (font, &x_scale, &y_scale); + cairo_scale (cr, +1./x_scale, -1./y_scale); + + hb_cairo_context_t c; + c.scaled_font = scaled_font; + c.cr = cr; + c.color_cache = (hb_map_t *) cairo_scaled_font_get_user_data (scaled_font, &color_cache_key); + + hb_font_paint_glyph (font, glyph, hb_cairo_paint_get_funcs (), &c, palette, color); + + + return CAIRO_STATUS_SUCCESS; +} + +#endif + +static cairo_font_face_t * +user_font_face_create (hb_face_t *face) +{ + cairo_font_face_t *cairo_face; + + cairo_face = cairo_user_font_face_create (); + cairo_user_font_face_set_init_func (cairo_face, hb_cairo_init_scaled_font); + cairo_user_font_face_set_text_to_glyphs_func (cairo_face, hb_cairo_text_to_glyphs); + cairo_user_font_face_set_render_glyph_func (cairo_face, hb_cairo_render_glyph); +#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC + if (hb_ot_color_has_png (face) || hb_ot_color_has_layers (face) || hb_ot_color_has_paint (face)) + cairo_user_font_face_set_render_color_glyph_func (cairo_face, hb_cairo_render_color_glyph); +#endif + + if (unlikely (CAIRO_STATUS_SUCCESS != cairo_font_face_set_user_data (cairo_face, + &hb_cairo_face_user_data_key, + (void *) hb_face_reference (face), + hb_cairo_face_destroy))) + hb_face_destroy (face); + + return cairo_face; +} + +/** + * hb_cairo_font_face_create_for_font: + * @font: a #hb_font_t + * + * Creates a #cairo_font_face_t for rendering text according + * to @font. + * + * Note that the scale of @font does not affect the rendering, + * but the variations and slant that are set on @font do. + * + * Returns: (transfer full): a newly created #cairo_font_face_t + * + * Since: 7.0.0 + */ +cairo_font_face_t * +hb_cairo_font_face_create_for_font (hb_font_t *font) +{ + hb_font_make_immutable (font); + + auto *cairo_face = user_font_face_create (font->face); + + if (unlikely (CAIRO_STATUS_SUCCESS != cairo_font_face_set_user_data (cairo_face, + &hb_cairo_font_user_data_key, + (void *) hb_font_reference (font), + hb_cairo_font_destroy))) + hb_font_destroy (font); + + return cairo_face; +} + +/** + * hb_cairo_font_face_get_font: + * @font_face: a #cairo_font_face_t + * + * Gets the #hb_font_t that @font_face was created from. + * + * Returns: (nullable) (transfer none): the #hb_font_t that @font_face was created from + * + * Since: 7.0.0 + */ +hb_font_t * +hb_cairo_font_face_get_font (cairo_font_face_t *font_face) +{ + return (hb_font_t *) cairo_font_face_get_user_data (font_face, + &hb_cairo_font_user_data_key); +} + +/** + * hb_cairo_font_face_create_for_face: + * @face: a #hb_face_t + * + * Creates a #cairo_font_face_t for rendering text according + * to @face. + * + * Returns: (transfer full): a newly created #cairo_font_face_t + * + * Since: 7.0.0 + */ +cairo_font_face_t * +hb_cairo_font_face_create_for_face (hb_face_t *face) +{ + hb_face_make_immutable (face); + + return user_font_face_create (face); +} + +/** + * hb_cairo_font_face_get_face: + * @font_face: a #cairo_font_face_t + * + * Gets the #hb_face_t associated with @font_face. + * + * Returns: (nullable) (transfer none): the #hb_face_t associated with @font_face + * + * Since: 7.0.0 + */ +hb_face_t * +hb_cairo_font_face_get_face (cairo_font_face_t *font_face) +{ + return (hb_face_t *) cairo_font_face_get_user_data (font_face, + &hb_cairo_face_user_data_key); +} + +/** + * hb_cairo_font_face_set_font_init_func: + * @font_face: a #cairo_font_face_t + * @func: The virtual method to use + * @user_data: user data accompanying the method + * @destroy: function to call when @user_data is not needed anymore + * + * Set the virtual method to be called when a cairo + * face created using hb_cairo_font_face_create_for_face() + * creates an #hb_font_t for a #cairo_scaled_font_t. + * + * Since: 7.0.0 + */ +void +hb_cairo_font_face_set_font_init_func (cairo_font_face_t *font_face, + hb_cairo_font_init_func_t func, + void *user_data, + hb_destroy_func_t destroy) +{ + cairo_font_face_set_user_data (font_face, + &hb_cairo_font_init_func_user_data_key, + (void *) func, + nullptr); + if (unlikely (CAIRO_STATUS_SUCCESS != cairo_font_face_set_user_data (font_face, + &hb_cairo_font_init_user_data_user_data_key, + (void *) user_data, + destroy)) && destroy) + { + destroy (user_data); + cairo_font_face_set_user_data (font_face, + &hb_cairo_font_init_func_user_data_key, + nullptr, + nullptr); + } +} + +/** + * hb_cairo_scaled_font_get_font: + * @scaled_font: a #cairo_scaled_font_t + * + * Gets the #hb_font_t associated with @scaled_font. + * + * Returns: (nullable) (transfer none): the #hb_font_t associated with @scaled_font + * + * Since: 7.0.0 + */ +hb_font_t * +hb_cairo_scaled_font_get_font (cairo_scaled_font_t *scaled_font) +{ + return (hb_font_t *) cairo_scaled_font_get_user_data (scaled_font, &hb_cairo_font_user_data_key); +} + + +/** + * hb_cairo_font_face_set_scale_factor: + * @scale_factor: The scale factor to use. See below + * @font_face: a #cairo_font_face_t + * + * Sets the scale factor of the @font_face. Default scale + * factor is zero. + * + * When a #cairo_font_face_t is created from a #hb_face_t using + * hb_cairo_font_face_create_for_face(), such face will create + * #hb_font_t objects during scaled-font creation. The scale + * factor defines how the scale set on such #hb_font_t objects + * relates to the font-matrix (as such font size) of the cairo + * scaled-font. + * + * If the scale-factor is zero (default), then the scale of the + * #hb_font_t object will be left at default, which is the UPEM + * value of the respective #hb_face_t. + * + * If the scale-factor is set to non-zero, then the X and Y scale + * of the #hb_font_t object will be respectively set to the + * @scale_factor times the xx and yy elements of the scale-matrix + * of the cairo scaled-font being created. + * + * When using the hb_cairo_glyphs_from_buffer() API to convert the + * HarfBuzz glyph buffer that resulted from shaping with such a #hb_font_t, + * if the scale-factor was non-zero, you can pass it directly to + * that API as both X and Y scale factors. + * + * If the scale-factor was zero however, or the cairo face was + * created using the alternative constructor + * hb_cairo_font_face_create_for_font(), you need to calculate the + * correct X/Y scale-factors to pass to hb_cairo_glyphs_from_buffer() + * by dividing the #hb_font_t X/Y scale-factors by the + * cairo scaled-font's scale-matrix XX/YY components respectively + * and use those values. Or if you know that relationship offhand + * (because you set the scale of the #hb_font_t yourself), use + * the conversion rate involved. + * + * Since: 7.0.0 + */ +void +hb_cairo_font_face_set_scale_factor (cairo_font_face_t *font_face, + unsigned int scale_factor) +{ + cairo_font_face_set_user_data (font_face, + &hb_cairo_scale_factor_user_data_key, + (void *) (uintptr_t) scale_factor, + nullptr); +} + +/** + * hb_cairo_font_face_get_scale_factor: + * @font_face: a #cairo_font_face_t + * + * Gets the scale factor set on the @font_face. Defaults to zero. + * See hb_cairo_font_face_set_scale_factor() for details. + * + * Returns: the scale factor of @font_face + * + * Since: 7.0.0 + */ +unsigned int +hb_cairo_font_face_get_scale_factor (cairo_font_face_t *font_face) +{ + return (unsigned int) (uintptr_t) + cairo_font_face_get_user_data (font_face, + &hb_cairo_scale_factor_user_data_key); +} + + +/** + * hb_cairo_glyphs_from_buffer: + * @buffer: a #hb_buffer_t containing glyphs + * @utf8_clusters: `true` if @buffer clusters are in bytes, instead of characters + * @x_scale_factor: scale factor to divide #hb_position_t Y values by + * @y_scale_factor: scale factor to divide #hb_position_t X values by + * @x: X position to place first glyph + * @y: Y position to place first glyph + * @utf8: (nullable): the text that was shaped in @buffer + * @utf8_len: the length of @utf8 in bytes + * @glyphs: (out): return location for an array of #cairo_glyph_t + * @num_glyphs: (inout): return location for the length of @glyphs + * @clusters: (out) (nullable): return location for an array of cluster positions + * @num_clusters: (inout) (nullable): return location for the length of @clusters + * @cluster_flags: (out) (nullable): return location for cluster flags + * + * Extracts information from @buffer in a form that can be + * passed to cairo_show_text_glyphs() or cairo_show_glyphs(). + * This API is modeled after cairo_scaled_font_text_to_glyphs() and + * cairo_user_scaled_font_text_to_glyphs_func_t. + * + * The @num_glyphs argument should be preset to the number of glyph entries available + * in the @glyphs buffer. If the @glyphs buffer is `NULL`, the value of + * @num_glyphs must be zero. If the provided glyph array is too short for + * the conversion (or for convenience), a new glyph array may be allocated + * using cairo_glyph_allocate() and placed in @glyphs. Upon return, + * @num_glyphs should contain the number of generated glyphs. If the value + * @glyphs points at has changed after the call, the caller will free the + * allocated glyph array using cairo_glyph_free(). The caller will also free + * the original value of @glyphs, so this function shouldn't do so. + * + * If @clusters is not `NULL`, then @num_clusters and @cluster_flags + * should not be either, and @utf8 must be provided, and cluster + * mapping will be computed. The semantics of how + * cluster array allocation works is similar to the glyph array. That is, + * if @clusters initially points to a non-`NULL` value, that array may be used + * as a cluster buffer, and @num_clusters points to the number of cluster + * entries available there. If the provided cluster array is too short for + * the conversion (or for convenience), a new cluster array may be allocated + * using cairo_text_cluster_allocate() and placed in @clusters. In this case, + * the original value of @clusters will still be freed by the caller. Upon + * return, @num_clusters will contain the number of generated clusters. + * If the value @clusters points at has changed after the call, the caller + * will free the allocated cluster array using cairo_text_cluster_free(). + * + * See hb_cairo_font_face_set_scale_factor() for the details of + * the @scale_factor argument. + * + * The returned @glyphs vector actually has `@num_glyphs + 1` entries in + * it and the x,y values of the extra entry at the end add up the advance + * x,y of all the glyphs in the @buffer. + * + * Since: 7.0.0 + */ +void +hb_cairo_glyphs_from_buffer (hb_buffer_t *buffer, + hb_bool_t utf8_clusters, + double x_scale_factor, + double y_scale_factor, + double x, + double y, + const char *utf8, + int utf8_len, + cairo_glyph_t **glyphs, + unsigned int *num_glyphs, + cairo_text_cluster_t **clusters, + unsigned int *num_clusters, + cairo_text_cluster_flags_t *cluster_flags) +{ + if (utf8 && utf8_len < 0) + utf8_len = strlen (utf8); + + unsigned orig_num_glyphs = *num_glyphs; + *num_glyphs = hb_buffer_get_length (buffer); + hb_glyph_info_t *hb_glyph = hb_buffer_get_glyph_infos (buffer, nullptr); + hb_glyph_position_t *hb_position = hb_buffer_get_glyph_positions (buffer, nullptr); + if (orig_num_glyphs < *num_glyphs + 1) + *glyphs = cairo_glyph_allocate (*num_glyphs + 1); + + if (clusters && utf8) + { + unsigned orig_num_clusters = *num_clusters; + *num_clusters = *num_glyphs ? 1 : 0; + for (unsigned int i = 1; i < *num_glyphs; i++) + if (hb_glyph[i].cluster != hb_glyph[i-1].cluster) + (*num_clusters)++; + if (orig_num_clusters < *num_clusters) + *clusters = cairo_text_cluster_allocate (*num_clusters); + } + + double x_scale = x_scale_factor ? 1. / x_scale_factor : 0.; + double y_scale = y_scale_factor ? 1. / y_scale_factor : 0.; + hb_position_t hx = 0, hy = 0; + int i; + for (i = 0; i < (int) *num_glyphs; i++) + { + (*glyphs)[i].index = hb_glyph[i].codepoint; + (*glyphs)[i].x = x + (+hb_position->x_offset + hx) * x_scale; + (*glyphs)[i].y = y + (-hb_position->y_offset + hy) * y_scale; + hx += hb_position->x_advance; + hy += -hb_position->y_advance; + + hb_position++; + } + (*glyphs)[i].index = -1; + (*glyphs)[i].x = round (hx * x_scale); + (*glyphs)[i].y = round (hy * y_scale); + + if (clusters && *num_clusters && utf8) + { + hb_memset ((void *) *clusters, 0, *num_clusters * sizeof ((*clusters)[0])); + hb_bool_t backward = HB_DIRECTION_IS_BACKWARD (hb_buffer_get_direction (buffer)); + *cluster_flags = backward ? CAIRO_TEXT_CLUSTER_FLAG_BACKWARD : (cairo_text_cluster_flags_t) 0; + unsigned int cluster = 0; + const char *start = utf8, *end; + (*clusters)[cluster].num_glyphs++; + if (backward) + { + for (i = *num_glyphs - 2; i >= 0; i--) + { + if (hb_glyph[i].cluster != hb_glyph[i+1].cluster) + { + assert (hb_glyph[i].cluster > hb_glyph[i+1].cluster); + if (utf8_clusters) + end = start + hb_glyph[i].cluster - hb_glyph[i+1].cluster; + else + end = (const char *) hb_utf_offset_to_pointer ((const uint8_t *) start, + (signed) (hb_glyph[i].cluster - hb_glyph[i+1].cluster)); + (*clusters)[cluster].num_bytes = end - start; + start = end; + cluster++; + } + (*clusters)[cluster].num_glyphs++; + } + (*clusters)[cluster].num_bytes = utf8 + utf8_len - start; + } + else + { + for (i = 1; i < (int) *num_glyphs; i++) + { + if (hb_glyph[i].cluster != hb_glyph[i-1].cluster) + { + assert (hb_glyph[i].cluster > hb_glyph[i-1].cluster); + if (utf8_clusters) + end = start + hb_glyph[i].cluster - hb_glyph[i-1].cluster; + else + end = (const char *) hb_utf_offset_to_pointer ((const uint8_t *) start, + (signed) (hb_glyph[i].cluster - hb_glyph[i-1].cluster)); + (*clusters)[cluster].num_bytes = end - start; + start = end; + cluster++; + } + (*clusters)[cluster].num_glyphs++; + } + (*clusters)[cluster].num_bytes = utf8 + utf8_len - start; + } + } + else if (num_clusters) + *num_clusters = 0; +} + +#endif diff --git a/libs/harfbuzz/src/hb-cairo.h b/libs/harfbuzz/src/hb-cairo.h new file mode 100644 index 000000000..21e284c8f --- /dev/null +++ b/libs/harfbuzz/src/hb-cairo.h @@ -0,0 +1,99 @@ +/* + * Copyright © 2022 Red Hat, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Matthias Clasen + */ + +#ifndef HB_CAIRO_H +#define HB_CAIRO_H + +#include "hb.h" + +#include + +HB_BEGIN_DECLS + +HB_EXTERN cairo_font_face_t * +hb_cairo_font_face_create_for_font (hb_font_t *font); + +HB_EXTERN hb_font_t * +hb_cairo_font_face_get_font (cairo_font_face_t *font_face); + +HB_EXTERN cairo_font_face_t * +hb_cairo_font_face_create_for_face (hb_face_t *face); + +HB_EXTERN hb_face_t * +hb_cairo_font_face_get_face (cairo_font_face_t *font_face); + +/** + * hb_cairo_font_init_func_t: + * @font: The #hb_font_t being created + * @scaled_font: The respective #cairo_scaled_font_t + * @user_data: User data accompanying this method + * + * The type of a virtual method to be called when a cairo + * face created using hb_cairo_font_face_create_for_face() + * creates an #hb_font_t for a #cairo_scaled_font_t. + * + * Return value: the #hb_font_t value to use; in most cases same as @font + * + * Since: 7.0.0 + */ +typedef hb_font_t * (*hb_cairo_font_init_func_t) (hb_font_t *font, + cairo_scaled_font_t *scaled_font, + void *user_data); + +HB_EXTERN void +hb_cairo_font_face_set_font_init_func (cairo_font_face_t *font_face, + hb_cairo_font_init_func_t func, + void *user_data, + hb_destroy_func_t destroy); + +HB_EXTERN hb_font_t * +hb_cairo_scaled_font_get_font (cairo_scaled_font_t *scaled_font); + +HB_EXTERN void +hb_cairo_font_face_set_scale_factor (cairo_font_face_t *font_face, + unsigned int scale_factor); + +HB_EXTERN unsigned int +hb_cairo_font_face_get_scale_factor (cairo_font_face_t *font_face); + +HB_EXTERN void +hb_cairo_glyphs_from_buffer (hb_buffer_t *buffer, + hb_bool_t utf8_clusters, + double x_scale_factor, + double y_scale_factor, + double x, + double y, + const char *utf8, + int utf8_len, + cairo_glyph_t **glyphs, + unsigned int *num_glyphs, + cairo_text_cluster_t **clusters, + unsigned int *num_clusters, + cairo_text_cluster_flags_t *cluster_flags); + +HB_END_DECLS + +#endif /* HB_CAIRO_H */ diff --git a/libs/harfbuzz/src/hb-cff-interp-common.hh b/libs/harfbuzz/src/hb-cff-interp-common.hh index 5c2cb060a..6ca7500af 100644 --- a/libs/harfbuzz/src/hb-cff-interp-common.hh +++ b/libs/harfbuzz/src/hb-cff-interp-common.hh @@ -26,6 +26,8 @@ #ifndef HB_CFF_INTERP_COMMON_HH #define HB_CFF_INTERP_COMMON_HH +extern HB_INTERNAL const unsigned char *endchar_str; + namespace CFF { using namespace OT; @@ -284,69 +286,58 @@ struct UnsizedByteStr : UnsizedArrayOf /* A byte string associated with the current offset and an error condition */ struct byte_str_ref_t { - byte_str_ref_t () { init (); } - - void init () - { - str = hb_ubytes_t (); - offset = 0; - error = false; - } - - void fini () {} + byte_str_ref_t () + : str () {} byte_str_ref_t (const hb_ubytes_t &str_, unsigned int offset_ = 0) - : str (str_), offset (offset_), error (false) {} + : str (str_) { set_offset (offset_); } void reset (const hb_ubytes_t &str_, unsigned int offset_ = 0) { str = str_; - offset = offset_; - error = false; + set_offset (offset_); } const unsigned char& operator [] (int i) { - if (unlikely ((unsigned int) (offset + i) >= str.length)) + if (unlikely ((unsigned int) (get_offset () + i) >= str.length)) { set_error (); return Null (unsigned char); } - return str[offset + i]; + return str.arrayZ[get_offset () + i]; } + unsigned char head_unchecked () const { return str.arrayZ[get_offset ()]; } + /* Conversion to hb_ubytes_t */ - operator hb_ubytes_t () const { return str.sub_array (offset, str.length - offset); } + operator hb_ubytes_t () const { return str.sub_array (get_offset ()); } hb_ubytes_t sub_array (unsigned int offset_, unsigned int len_) const { return str.sub_array (offset_, len_); } bool avail (unsigned int count=1) const - { return (!in_error () && offset + count <= str.length); } + { return get_offset () + count <= str.length; } void inc (unsigned int count=1) { - if (likely (!in_error () && (offset <= str.length) && (offset + count <= str.length))) - { - offset += count; - } - else - { - offset = str.length; - set_error (); - } + /* Automatically puts us in error if count is out-of-range. */ + set_offset (get_offset () + count); } - void set_error () { error = true; } - bool in_error () const { return error; } + /* We (ab)use ubytes backwards_length as a cursor (called offset), + * as well as to store error condition. */ - hb_ubytes_t str; - unsigned int offset; /* beginning of the sub-string within str */ + unsigned get_offset () const { return str.backwards_length; } + void set_offset (unsigned offset) { str.backwards_length = offset; } + + void set_error () { str.backwards_length = str.length + 1; } + bool in_error () const { return str.backwards_length > str.length; } + + unsigned total_size () const { return str.length; } protected: - bool error; + hb_ubytes_t str; }; -using byte_str_array_t = hb_vector_t; - /* stack */ template struct cff_stack_t @@ -491,8 +482,15 @@ struct arg_stack_t : cff_stack_t /* an operator prefixed by its operands in a byte string */ struct op_str_t { - hb_ubytes_t str; - op_code_t op; + /* This used to have a hb_ubytes_t. Using a pointer and length + * in a particular order, saves 8 bytes in this struct and more + * in our parsed_cs_op_t subclass. */ + + const unsigned char *ptr = nullptr; + + op_code_t op = OpCode_Invalid; + + uint8_t length = 0; }; /* base of OP_SERIALIZER */ @@ -503,9 +501,11 @@ struct op_serializer_t { TRACE_SERIALIZE (this); - HBUINT8 *d = c->allocate_size (opstr.str.length); + unsigned char *d = c->allocate_size (opstr.length); if (unlikely (!d)) return_trace (false); - memcpy (d, &opstr.str[0], opstr.str.length); + /* Faster than hb_memcpy for small strings. */ + for (unsigned i = 0; i < opstr.length; i++) + d[i] = opstr.ptr[i]; return_trace (true); } }; @@ -522,23 +522,17 @@ struct parsed_values_t void alloc (unsigned n) { - values.alloc (n); + values.alloc (n, true); } - void add_op (op_code_t op, const byte_str_ref_t& str_ref = byte_str_ref_t ()) - { - VAL *val = values.push (); - val->op = op; - val->str = str_ref.str.sub_array (opStart, str_ref.offset - opStart); - opStart = str_ref.offset; - } - - void add_op (op_code_t op, const byte_str_ref_t& str_ref, const VAL &v) + void add_op (op_code_t op, const byte_str_ref_t& str_ref = byte_str_ref_t (), const VAL &v = VAL ()) { VAL *val = values.push (v); val->op = op; - val->str = str_ref.sub_array ( opStart, str_ref.offset - opStart); - opStart = str_ref.offset; + auto arr = str_ref.sub_array (opStart, str_ref.get_offset () - opStart); + val->ptr = arr.arrayZ; + val->length = arr.length; + opStart = str_ref.get_offset (); } bool has_op (op_code_t op) const @@ -549,8 +543,7 @@ struct parsed_values_t } unsigned get_count () const { return values.length; } - const VAL &get_value (unsigned int i) const { return values[i]; } - const VAL &operator [] (unsigned int i) const { return get_value (i); } + const VAL &operator [] (unsigned int i) const { return values[i]; } unsigned int opStart; hb_vector_t values; @@ -565,23 +558,23 @@ struct interp_env_t str_ref.reset (str_); } bool in_error () const - { return error || str_ref.in_error () || argStack.in_error (); } + { return str_ref.in_error () || argStack.in_error (); } - void set_error () { error = true; } + void set_error () { str_ref.set_error (); } op_code_t fetch_op () { op_code_t op = OpCode_Invalid; if (unlikely (!str_ref.avail ())) return OpCode_Invalid; - op = (op_code_t)(unsigned char)str_ref[0]; + op = (op_code_t) str_ref.head_unchecked (); + str_ref.inc (); if (op == OpCode_escape) { if (unlikely (!str_ref.avail ())) return OpCode_Invalid; - op = Make_OpCode_ESC(str_ref[1]); + op = Make_OpCode_ESC (str_ref.head_unchecked ()); str_ref.inc (); } - str_ref.inc (); return op; } @@ -596,8 +589,6 @@ struct interp_env_t str_ref; arg_stack_t argStack; - protected: - bool error = false; }; using num_interp_env_t = interp_env_t<>; @@ -633,7 +624,6 @@ struct opset_t } else { /* invalid unknown operator */ env.clear_args (); - env.set_error (); } break; } diff --git a/libs/harfbuzz/src/hb-cff-interp-cs-common.hh b/libs/harfbuzz/src/hb-cff-interp-cs-common.hh index f93c83ab4..28a777eb0 100644 --- a/libs/harfbuzz/src/hb-cff-interp-cs-common.hh +++ b/libs/harfbuzz/src/hb-cff-interp-cs-common.hh @@ -57,7 +57,6 @@ struct call_context_t /* call stack */ const unsigned int kMaxCallLimit = 10; -const unsigned int kMaxOps = 10000; struct call_stack_t : cff_stack_t {}; template @@ -882,16 +881,14 @@ struct cs_interpreter_t : interpreter_t { SUPER::env.set_endchar (false); - unsigned max_ops = kMaxOps; + unsigned max_ops = HB_CFF_MAX_OPS; for (;;) { - if (unlikely (!--max_ops)) + OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param); + if (unlikely (SUPER::env.in_error () || !--max_ops)) { SUPER::env.set_error (); - break; - } - OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param); - if (unlikely (SUPER::env.in_error ())) return false; + } if (SUPER::env.is_endchar ()) break; } diff --git a/libs/harfbuzz/src/hb-cff-interp-dict-common.hh b/libs/harfbuzz/src/hb-cff-interp-dict-common.hh index 79fe9b42c..b513a1e8c 100644 --- a/libs/harfbuzz/src/hb-cff-interp-dict-common.hh +++ b/libs/harfbuzz/src/hb-cff-interp-dict-common.hh @@ -35,10 +35,8 @@ using namespace OT; /* an opstr and the parsed out dict value(s) */ struct dict_val_t : op_str_t { - void init () { single_val.set_int (0); } + void init () {} void fini () {} - - number_t single_val; }; typedef dict_val_t num_dict_val_t; @@ -56,8 +54,8 @@ struct top_dict_values_t : dict_values_t } void fini () { dict_values_t::fini (); } - unsigned int charStringsOffset; - unsigned int FDArrayOffset; + int charStringsOffset; + int FDArrayOffset; }; struct dict_opset_t : opset_t @@ -86,7 +84,7 @@ struct dict_opset_t : opset_t enum Nibble { DECIMAL=10, EXP_POS, EXP_NEG, RESERVED, NEG, END }; - char buf[32]; + char buf[32] = {0}; unsigned char byte = 0; for (unsigned i = 0, count = 0; count < ARRAY_LENGTH (buf); ++i, ++count) { @@ -159,11 +157,11 @@ struct top_dict_opset_t : dict_opset_t { switch (op) { case OpCode_CharStrings: - dictval.charStringsOffset = env.argStack.pop_uint (); + dictval.charStringsOffset = env.argStack.pop_int (); env.clear_args (); break; case OpCode_FDArray: - dictval.FDArrayOffset = env.argStack.pop_uint (); + dictval.FDArrayOffset = env.argStack.pop_int (); env.clear_args (); break; case OpCode_FontMatrix: diff --git a/libs/harfbuzz/src/hb-cff1-interp-cs.hh b/libs/harfbuzz/src/hb-cff1-interp-cs.hh index b306c2ecc..d8868efa5 100644 --- a/libs/harfbuzz/src/hb-cff1-interp-cs.hh +++ b/libs/harfbuzz/src/hb-cff1-interp-cs.hh @@ -38,7 +38,8 @@ typedef biased_subrs_t cff1_biased_subrs_t; struct cff1_cs_interp_env_t : cs_interp_env_t { template - cff1_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd) + cff1_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) { processed_width = false; diff --git a/libs/harfbuzz/src/hb-cff2-interp-cs.hh b/libs/harfbuzz/src/hb-cff2-interp-cs.hh index d0b9e7b08..06fbb72c6 100644 --- a/libs/harfbuzz/src/hb-cff2-interp-cs.hh +++ b/libs/harfbuzz/src/hb-cff2-interp-cs.hh @@ -40,20 +40,22 @@ struct blend_arg_t : number_t void set_real (double v) { reset_blends (); number_t::set_real (v); } void set_blends (unsigned int numValues_, unsigned int valueIndex_, - unsigned int numBlends, hb_array_t blends_) + hb_array_t blends_) { numValues = numValues_; valueIndex = valueIndex_; - deltas.resize (numBlends); + unsigned numBlends = blends_.length; + if (unlikely (!deltas.resize_exact (numBlends))) + return; for (unsigned int i = 0; i < numBlends; i++) - deltas[i] = blends_[i]; + deltas.arrayZ[i] = blends_.arrayZ[i]; } bool blending () const { return deltas.length > 0; } void reset_blends () { numValues = valueIndex = 0; - deltas.resize (0); + deltas.shrink (0); } unsigned int numValues; @@ -61,7 +63,6 @@ struct blend_arg_t : number_t hb_vector_t deltas; }; -typedef interp_env_t BlendInterpEnv; typedef biased_subrs_t cff2_biased_subrs_t; template @@ -75,16 +76,12 @@ struct cff2_cs_interp_env_t : cs_interp_env_t coords = coords_; num_coords = num_coords_; varStore = acc.varStore; - seen_blend = false; - seen_vsindex_ = false; - scalars.init (); do_blend = num_coords && coords && varStore->size; set_ivs (acc.privateDicts[fd].ivs); } void fini () { - scalars.fini (); SUPER::fini (); } @@ -117,7 +114,7 @@ struct cff2_cs_interp_env_t : cs_interp_env_t region_count = varStore->varStore.get_region_index_count (get_ivs ()); if (do_blend) { - if (unlikely (!scalars.resize (region_count))) + if (unlikely (!scalars.resize_exact (region_count))) SUPER::set_error (); else varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords, @@ -154,23 +151,26 @@ struct cff2_cs_interp_env_t : cs_interp_env_t { if (likely (scalars.length == deltas.length)) { - for (unsigned int i = 0; i < scalars.length; i++) - v += (double) scalars[i] * deltas[i].to_real (); + unsigned count = scalars.length; + for (unsigned i = 0; i < count; i++) + v += (double) scalars.arrayZ[i] * deltas.arrayZ[i].to_real (); } } return v; } + bool have_coords () const { return num_coords; } + protected: const int *coords; unsigned int num_coords; - const CFF2VariationStore *varStore; + const CFF2ItemVariationStore *varStore; unsigned int region_count; unsigned int ivs; hb_vector_t scalars; bool do_blend; - bool seen_vsindex_; - bool seen_blend; + bool seen_vsindex_ = false; + bool seen_blend = false; typedef cs_interp_env_t SUPER; }; @@ -220,7 +220,10 @@ struct cff2_cs_opset_t : cs_opset_t, PAR const hb_array_t blends, unsigned n, unsigned i) { - arg.set_blends (n, i, blends.length, blends); + if (env.have_coords ()) + arg.set_int (round (arg.to_real () + env.blend_deltas (blends))); + else + arg.set_blends (n, i, blends); } template diff --git a/libs/harfbuzz/src/hb-common.cc b/libs/harfbuzz/src/hb-common.cc index bbb6cd552..4b8bae442 100644 --- a/libs/harfbuzz/src/hb-common.cc +++ b/libs/harfbuzz/src/hb-common.cc @@ -29,32 +29,6 @@ #include "hb.hh" #include "hb-machinery.hh" -#if !defined(HB_NO_SETLOCALE) && (!defined(HAVE_NEWLOCALE) || !defined(HAVE_USELOCALE)) -#define HB_NO_SETLOCALE 1 -#endif - -#ifndef HB_NO_SETLOCALE - -#include -#ifdef HAVE_XLOCALE_H -#include // Needed on BSD/OS X for uselocale -#endif - -#ifdef WIN32 -#define hb_locale_t _locale_t -#else -#define hb_locale_t locale_t -#endif -#define hb_setlocale setlocale -#define hb_uselocale uselocale - -#else - -#define hb_locale_t void * -#define hb_setlocale(Category, Locale) "C" -#define hb_uselocale(Locale) ((hb_locale_t) 0) - -#endif /** * SECTION:hb-common @@ -285,7 +259,7 @@ struct hb_language_item_t { lang = (hb_language_t) hb_malloc(len); if (likely (lang)) { - memcpy((unsigned char *) lang, s, len); + hb_memcpy((unsigned char *) lang, s, len); for (unsigned char *p = (unsigned char *) lang; *p; p++) *p = canon_map[*p]; } @@ -379,7 +353,7 @@ hb_language_from_string (const char *str, int len) /* NUL-terminate it. */ char strbuf[64]; len = hb_min (len, (int) sizeof (strbuf) - 1); - memcpy (strbuf, str, len); + hb_memcpy (strbuf, str, len); strbuf[len] = '\0'; item = lang_find_or_insert (strbuf); } @@ -658,6 +632,7 @@ hb_script_get_horizontal_direction (hb_script_t script) case HB_SCRIPT_OLD_HUNGARIAN: case HB_SCRIPT_OLD_ITALIC: case HB_SCRIPT_RUNIC: + case HB_SCRIPT_TIFINAGH: return HB_DIRECTION_INVALID; } @@ -840,7 +815,7 @@ parse_tag (const char **pp, const char *end, hb_tag_t *tag) } const char *p = *pp; - while (*pp < end && (ISALNUM(**pp) || **pp == '_')) + while (*pp < end && (**pp != ' ' && **pp != '=' && **pp != '[' && **pp != quote)) (*pp)++; if (p == *pp || *pp - p > 4) @@ -976,7 +951,7 @@ hb_feature_from_string (const char *str, int len, } if (feature) - memset (feature, 0, sizeof (*feature)); + hb_memset (feature, 0, sizeof (*feature)); return false; } @@ -1021,11 +996,11 @@ hb_feature_to_string (hb_feature_t *feature, if (feature->value > 1) { s[len++] = '='; - len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value)); + len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%" PRIu32, feature->value)); } assert (len < ARRAY_LENGTH (s)); len = hb_min (len, size - 1); - memcpy (buf, s, len); + hb_memcpy (buf, s, len); buf[len] = '\0'; } @@ -1088,7 +1063,7 @@ hb_variation_from_string (const char *str, int len, } if (variation) - memset (variation, 0, sizeof (*variation)); + hb_memset (variation, 0, sizeof (*variation)); return false; } @@ -1136,7 +1111,7 @@ get_C_locale () /** * hb_variation_to_string: * @variation: an #hb_variation_t to convert - * @buf: (array length=size) (out): output string + * @buf: (array length=size) (out caller-allocates): output string * @size: the allocated size of @buf * * Converts an #hb_variation_t into a `NULL`-terminated string in the format @@ -1166,7 +1141,7 @@ hb_variation_to_string (hb_variation_t *variation, assert (len < ARRAY_LENGTH (s)); len = hb_min (len, size - 1); - memcpy (buf, s, len); + hb_memcpy (buf, s, len); buf[len] = '\0'; } diff --git a/libs/harfbuzz/src/hb-common.h b/libs/harfbuzz/src/hb-common.h index e92feb989..110854548 100644 --- a/libs/harfbuzz/src/hb-common.h +++ b/libs/harfbuzz/src/hb-common.h @@ -47,14 +47,10 @@ # endif /* !__cplusplus */ #endif -#if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || \ - defined (_sgi) || defined (__sun) || defined (sun) || \ - defined (__digital__) || defined (__HP_cc) -# include -#elif defined (_AIX) +#if defined (_AIX) # include #elif defined (_MSC_VER) && _MSC_VER < 1600 -/* VS 2010 (_MSC_VER 1600) has stdint.h */ +/* VS 2010 (_MSC_VER 1600) has stdint.h */ typedef __int8 int8_t; typedef unsigned __int8 uint8_t; typedef __int16 int16_t; @@ -63,10 +59,11 @@ typedef __int32 int32_t; typedef unsigned __int32 uint32_t; typedef __int64 int64_t; typedef unsigned __int64 uint64_t; -#elif defined (__KERNEL__) -# include -#else +#elif defined (_MSC_VER) && _MSC_VER < 1800 +/* VS 2013 (_MSC_VER 1800) has inttypes.h */ # include +#else +# include #endif #if defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) @@ -104,6 +101,16 @@ typedef int hb_bool_t; * **/ typedef uint32_t hb_codepoint_t; + +/** + * HB_CODEPOINT_INVALID: + * + * Unused #hb_codepoint_t value. + * + * Since: 8.0.0 + */ +#define HB_CODEPOINT_INVALID ((hb_codepoint_t) -1) + /** * hb_position_t: * @@ -497,6 +504,13 @@ hb_language_matches (hb_language_t language, * @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 @@ -724,6 +738,17 @@ typedef enum 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, @@ -897,6 +922,32 @@ HB_EXTERN uint8_t hb_color_get_blue (hb_color_t color); #define hb_color_get_blue(color) (((color) >> 24) & 0xFF) +/** + * hb_glyph_extents_t: + * @x_bearing: Distance from the x-origin to the left extremum of the glyph. + * @y_bearing: Distance from the top extremum of the glyph to the y-origin. + * @width: Distance from the left extremum of the glyph to the right extremum. + * @height: Distance from the top extremum of the glyph to the bottom extremum. + * + * Glyph extent values, measured in font units. + * + * Note that @height is negative, in coordinate systems that grow up. + **/ +typedef struct hb_glyph_extents_t { + hb_position_t x_bearing; + hb_position_t y_bearing; + hb_position_t width; + hb_position_t height; +} hb_glyph_extents_t; + +/** + * hb_font_t: + * + * Data type for holding fonts. + * + */ +typedef struct hb_font_t hb_font_t; + HB_END_DECLS #endif /* HB_COMMON_H */ diff --git a/libs/harfbuzz/src/hb-config.hh b/libs/harfbuzz/src/hb-config.hh index d56617f6a..14105846a 100644 --- a/libs/harfbuzz/src/hb-config.hh +++ b/libs/harfbuzz/src/hb-config.hh @@ -35,26 +35,27 @@ #include "config.h" #endif -#ifndef HB_BORING_EXPANSION -#define HB_NO_BORING_EXPANSION +#ifndef HB_EXPERIMENTAL_API +#define HB_NO_BEYOND_64K +#define HB_NO_CUBIC_GLYF +#define HB_NO_VAR_COMPOSITES #endif #ifdef HB_TINY #define HB_LEAN #define HB_MINI +#define HB_OPTIMIZE_SIZE +#define HB_OPTIMIZE_SIZE_MORE +#define HB_MINIMIZE_MEMORY_USAGE #define HB_NO_MT #define HB_NO_UCD_UNASSIGNED #ifndef NDEBUG #define NDEBUG #endif -#ifndef __OPTIMIZE_SIZE__ -#define __OPTIMIZE_SIZE__ -#endif #endif #ifdef HB_LEAN #define HB_DISABLE_DEPRECATED -#define HB_NDEBUG #define HB_NO_ATEXIT #define HB_NO_BUFFER_MESSAGE #define HB_NO_BUFFER_SERIALIZE @@ -79,11 +80,13 @@ #define HB_NO_MMAP #define HB_NO_NAME #define HB_NO_OPEN -#define HB_NO_SETLOCALE #define HB_NO_OT_FONT_GLYPH_NAMES #define HB_NO_OT_SHAPE_FRACTIONS +#define HB_NO_PAINT +#define HB_NO_SETLOCALE #define HB_NO_STYLE #define HB_NO_SUBSET_LAYOUT +#define HB_NO_VERTICAL #define HB_NO_VAR #endif @@ -93,6 +96,12 @@ #define HB_NO_BORING_EXPANSION #endif +#ifdef __OPTIMIZE_SIZE__ +#ifndef HB_OPTIMIZE_SIZE +#define HB_OPTIMIZE_SIZE +#endif +#endif + #if defined(HAVE_CONFIG_OVERRIDE_H) || defined(HB_CONFIG_OVERRIDE_H) #ifndef HB_CONFIG_OVERRIDE_H #define HB_CONFIG_OVERRIDE_H "config-override.h" @@ -104,7 +113,12 @@ #ifdef HB_NO_BORING_EXPANSION #define HB_NO_BEYOND_64K -#define HB_NO_VARIATIONS2 +#define HB_NO_CUBIC_GLYF +#define HB_NO_VAR_COMPOSITES +#endif + +#ifdef HB_NO_VAR +#define HB_NO_VAR_COMPOSITES #endif #ifdef HB_DISABLE_DEPRECATED @@ -113,6 +127,11 @@ #define HB_IF_NOT_DEPRECATED(x) x #endif +#ifdef HB_NO_SHAPER +#define HB_NO_OT_SHAPE +#define HB_NO_AAT_SHAPE +#endif + #ifdef HB_NO_AAT #define HB_NO_OT_NAME_LANGUAGE_AAT #define HB_NO_AAT_SHAPE @@ -127,6 +146,10 @@ #define HB_NO_SUBSET_CFF #endif +#ifdef HB_NO_DRAW +#define HB_NO_OUTLINE +#endif + #ifdef HB_NO_GETENV #define HB_NO_UNISCRIBE_BUG_COMPATIBLE #endif @@ -159,23 +182,30 @@ #define HB_NO_OT_SHAPER_HEBREW_FALLBACK #define HB_NO_OT_SHAPER_THAI_FALLBACK #define HB_NO_OT_SHAPER_VOWEL_CONSTRAINTS +#define HB_NO_OT_SHAPER_MYANMAR_ZAWGYI #endif -#ifdef NDEBUG -#ifndef HB_NDEBUG -#define HB_NDEBUG -#endif +#ifdef HB_OPTIMIZE_SIZE_MORE +#define HB_NO_OT_RULESETS_FAST_PATH #endif -#ifdef __OPTIMIZE_SIZE__ -#ifndef HB_OPTIMIZE_SIZE -#define HB_OPTIMIZE_SIZE -#endif +#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 #ifdef HB_OPTIMIZE_SIZE -#define HB_NO_OT_LAYOUT_LOOKUP_CACHE +#define HB_OPTIMIZE_SIZE_VAL 1 +#else +#define HB_OPTIMIZE_SIZE_VAL 0 #endif +#ifdef HB_MINIMIZE_MEMORY_USAGE +#define HB_MINIMIZE_MEMORY_USAGE_VAL 1 +#else +#define HB_MINIMIZE_MEMORY_USAGE_VAL 0 +#endif #endif /* HB_CONFIG_HH */ diff --git a/libs/harfbuzz/src/hb-coretext-font.cc b/libs/harfbuzz/src/hb-coretext-font.cc new file mode 100644 index 000000000..e6a02cce6 --- /dev/null +++ b/libs/harfbuzz/src/hb-coretext-font.cc @@ -0,0 +1,461 @@ +/* + * Copyright © 2024 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Author(s): Behdad Esfahbod + */ + +#include "hb.hh" + +#ifdef HAVE_CORETEXT + +#include "hb-coretext.h" + +#include "hb-draw.hh" +#include "hb-font.hh" +#include "hb-machinery.hh" + +#if MAC_OS_X_VERSION_MIN_REQUIRED < 101100 +# define kCTFontOrientationDefault kCTFontDefaultOrientation +#endif + +#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 HB_UNUSED, + void *font_data, + hb_codepoint_t unicode, + hb_codepoint_t *glyph, + void *user_data HB_UNUSED) +{ + CTFontRef ct_font = (CTFontRef) font_data; + UniChar ch = unicode; + CGGlyph cg_glyph; + if (CTFontGetGlyphsForCharacters (ct_font, &ch, &cg_glyph, 1)) + { + *glyph = cg_glyph; + return true; + } + return false; +} + +static unsigned int +hb_coretext_get_nominal_glyphs (hb_font_t *font HB_UNUSED, + void *font_data, + 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) +{ + CTFontRef ct_font = (CTFontRef) font_data; + + UniChar ch[MAX_GLYPHS]; + CGGlyph cg_glyph[MAX_GLYPHS]; + for (unsigned i = 0; i < count; i += MAX_GLYPHS) + { + unsigned c = (unsigned) hb_min ((int) MAX_GLYPHS, (int) count - (int) i); + for (unsigned j = 0; j < c; j++) + { + ch[j] = *first_unicode; + first_unicode = &StructAtOffset (first_unicode, unicode_stride); + } + CTFontGetGlyphsForCharacters (ct_font, ch, cg_glyph, c); + for (unsigned j = 0; j < c; j++) + { + *first_glyph = cg_glyph[j]; + first_glyph = &StructAtOffset (first_glyph, glyph_stride); + } + } + + return count; +} + +static hb_bool_t +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) font_data; + + UniChar ch[2] = { unicode, variation_selector }; + CGGlyph cg_glyph[2]; + + CTFontGetGlyphsForCharacters (ct_font, ch, cg_glyph, 2); + + if (cg_glyph[1]) + return false; + + *glyph = cg_glyph[0]; + return true; +} + +static void +hb_coretext_get_glyph_h_advances (hb_font_t* font, void* font_data, + unsigned count, + const hb_codepoint_t *first_glyph, + unsigned glyph_stride, + hb_position_t *first_advance, + unsigned advance_stride, + void *user_data HB_UNUSED) +{ + CTFontRef ct_font = (CTFontRef) font_data; + + CGFloat ct_font_size = CTFontGetSize (ct_font); + CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size; + + CGGlyph cg_glyph[MAX_GLYPHS]; + CGSize advances[MAX_GLYPHS]; + for (unsigned i = 0; i < count; i += MAX_GLYPHS) + { + unsigned c = (unsigned) hb_min ((int) MAX_GLYPHS, (int) count - (int) i); + for (unsigned j = 0; j < c; j++) + { + cg_glyph[j] = *first_glyph; + first_glyph = &StructAtOffset (first_glyph, glyph_stride); + } + CTFontGetAdvancesForGlyphs (ct_font, kCTFontOrientationHorizontal, cg_glyph, advances, c); + for (unsigned j = 0; j < c; j++) + { + *first_advance = round (advances[j].width * x_mult); + first_advance = &StructAtOffset (first_advance, advance_stride); + } + } +} + +#ifndef HB_NO_VERTICAL +static void +hb_coretext_get_glyph_v_advances (hb_font_t* font, void* font_data, + unsigned count, + const hb_codepoint_t *first_glyph, + unsigned glyph_stride, + hb_position_t *first_advance, + unsigned advance_stride, + void *user_data HB_UNUSED) +{ + CTFontRef ct_font = (CTFontRef) font_data; + + CGFloat ct_font_size = CTFontGetSize (ct_font); + CGFloat y_mult = (CGFloat) -font->y_scale / ct_font_size; + + CGGlyph cg_glyph[MAX_GLYPHS]; + CGSize advances[MAX_GLYPHS]; + for (unsigned i = 0; i < count; i += MAX_GLYPHS) + { + unsigned c = (unsigned) hb_min ((int) MAX_GLYPHS, (int) count - (int) i); + for (unsigned j = 0; j < c; j++) + { + cg_glyph[j] = *first_glyph; + first_glyph = &StructAtOffset (first_glyph, glyph_stride); + } + CTFontGetAdvancesForGlyphs (ct_font, kCTFontOrientationVertical, cg_glyph, advances, c); + for (unsigned j = 0; j < c; j++) + { + *first_advance = round (advances[j].width * y_mult); + first_advance = &StructAtOffset (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_codepoint_t glyph, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) +{ + CTFontRef ct_font = (CTFontRef) font_data; + + CGFloat ct_font_size = CTFontGetSize (ct_font); + CGFloat x_mult = (CGFloat) -font->x_scale / ct_font_size; + CGFloat y_mult = (CGFloat) -font->y_scale / ct_font_size; + + const CGGlyph glyphs = glyph; + CGSize origin; + CTFontGetVerticalTranslationsForGlyphs (ct_font, &glyphs, &origin, 1); + + *x = round (x_mult * origin.width); + *y = round (y_mult * origin.height); + + return true; +} +#endif + +static hb_bool_t +hb_coretext_get_glyph_extents (hb_font_t *font, + void *font_data, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents, + void *user_data HB_UNUSED) +{ + CTFontRef ct_font = (CTFontRef) font_data; + + CGFloat ct_font_size = CTFontGetSize (ct_font); + CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size; + CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size; + + CGGlyph glyphs[1] = { glyph }; + CGRect bounds = ::CTFontGetBoundingRectsForGlyphs(ct_font, + kCTFontOrientationDefault, glyphs, NULL, 1); + + extents->x_bearing = round (bounds.origin.x * x_mult); + extents->y_bearing = round (bounds.origin.y * y_mult); + extents->width = round (bounds.size.width * x_mult); + 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_font_extents_t *metrics, + void *user_data HB_UNUSED) +{ + CTFontRef ct_font = (CTFontRef) font_data; + CGFloat ct_font_size = CTFontGetSize (ct_font); + CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size; + + metrics->ascender = round (CTFontGetAscent (ct_font) * y_mult); + metrics->descender = -round (CTFontGetDescent (ct_font) * y_mult); + metrics->line_gap = round (CTFontGetLeading (ct_font) * y_mult); + + return true; +} + +#ifndef HB_NO_DRAW + +static void +ct_apply_func (void *info, const CGPathElement *element) +{ + hb_draw_session_t *draws = (hb_draw_session_t *) info; + + switch (element->type) + { + case kCGPathElementMoveToPoint: + draws->move_to (element->points[0].x, element->points[0].y); + break; + case kCGPathElementAddLineToPoint: + draws->line_to (element->points[0].x, element->points[0].y); + break; + case kCGPathElementAddQuadCurveToPoint: + draws->quadratic_to (element->points[0].x, element->points[0].y, + element->points[1].x, element->points[1].y); + break; + case kCGPathElementAddCurveToPoint: + draws->cubic_to (element->points[0].x, element->points[0].y, + element->points[1].x, element->points[1].y, + element->points[2].x, element->points[2].y); + break; + case kCGPathElementCloseSubpath: + draws->close_path (); + break; + } +} + +static void +hb_coretext_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) +{ + CTFontRef ct_font = (CTFontRef) font_data; + + CGFloat ct_font_size = CTFontGetSize (ct_font); + CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size; + CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size; + + CGAffineTransform transform = CGAffineTransformIdentity; + transform = CGAffineTransformScale (transform, x_mult, y_mult); + + CGPathRef path = CTFontCreatePathForGlyph (ct_font, glyph, &transform); + if (!path) + return; + + hb_draw_session_t drawing = {draw_funcs, draw_data, font->slant}; + + CGPathApply (path, &drawing, ct_apply_func); + + CFRelease (path); +} +#endif + +static hb_bool_t +hb_coretext_get_glyph_name (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + char *name, unsigned int size, + void *user_data HB_UNUSED) +{ + CGFontRef cg_font = (CGFontRef) (const void *) font->face->data.coretext; + + CGGlyph cg_glyph = glyph; + CFStringRef cf_name = CGFontCopyGlyphNameForGlyph (cg_font, cg_glyph); + if (!cf_name) + return false; + + CFIndex len = CFStringGetLength (cf_name); + if (len > size - 1) + len = size - 1; + + CFStringGetBytes (cf_name, CFRangeMake (0, len), + kCFStringEncodingUTF8, 0, false, + (UInt8 *) name, size, &len); + + name[len] = '\0'; + return true; +} + +static hb_bool_t +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) font_data; + + if (len == -1) + len = strlen (name); + + CFStringRef cf_name = CFStringCreateWithBytes (kCFAllocatorDefault, + (const UInt8 *) name, len, + kCFStringEncodingUTF8, false); + CGGlyph cg_glyph = CTFontGetGlyphWithName (ct_font, cf_name); + *glyph = cg_glyph; + + CFRelease (cf_name); + + // TODO Return true for .notdef; hb-ft does that. + + return cg_glyph != 0; +} + + +static inline void free_static_coretext_funcs (); + +static struct hb_coretext_font_funcs_lazy_loader_t : hb_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_glyph_func (funcs, hb_coretext_get_nominal_glyph, nullptr, nullptr); + hb_font_funcs_set_nominal_glyphs_func (funcs, hb_coretext_get_nominal_glyphs, nullptr, nullptr); + hb_font_funcs_set_variation_glyph_func (funcs, hb_coretext_get_variation_glyph, nullptr, nullptr); + + 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 + +#ifndef HB_NO_DRAW + hb_font_funcs_set_draw_glyph_func (funcs, hb_coretext_draw_glyph, nullptr, nullptr); +#endif + + hb_font_funcs_set_glyph_extents_func (funcs, hb_coretext_get_glyph_extents, nullptr, nullptr); + +#ifndef HB_NO_OT_FONT_GLYPH_NAMES + hb_font_funcs_set_glyph_name_func (funcs, hb_coretext_get_glyph_name, nullptr, nullptr); + hb_font_funcs_set_glyph_from_name_func (funcs, hb_coretext_get_glyph_from_name, nullptr, nullptr); +#endif + + hb_font_funcs_make_immutable (funcs); + + hb_atexit (free_static_coretext_funcs); + + return funcs; + } +} static_coretext_funcs; + +static inline +void free_static_coretext_funcs () +{ + static_coretext_funcs.free_instance (); +} + +static hb_font_funcs_t * +_hb_coretext_get_font_funcs () +{ + return static_coretext_funcs.get_unconst (); +} + + +/** + * hb_coretext_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 CoreText font functions. + * + * In particular, you can use this function to configure an + * existing #hb_face_t face object for use with CoreText 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 CoreText font functions. + * + * An #hb_font_t object created with hb_coretext_font_create() + * is preconfigured for CoreText font functions and does not + * require this function to be used. + * + * Note: Internally, this function creates a CTFont. +* + * + * Since: 10.1.0 + **/ +void +hb_coretext_font_set_funcs (hb_font_t *font) +{ + CTFontRef ct_font = hb_coretext_font_get_ct_font (font); + if (unlikely (!ct_font)) + return; + + hb_font_set_funcs (font, + _hb_coretext_get_font_funcs (), + (void *) CFRetain (ct_font), + _hb_coretext_font_destroy); +} + +#undef MAX_GLYPHS + +#endif diff --git a/libs/harfbuzz/src/hb-coretext.cc b/libs/harfbuzz/src/hb-coretext-shape.cc similarity index 90% rename from libs/harfbuzz/src/hb-coretext.cc rename to libs/harfbuzz/src/hb-coretext-shape.cc index 99b33c001..73443796d 100644 --- a/libs/harfbuzz/src/hb-coretext.cc +++ b/libs/harfbuzz/src/hb-coretext-shape.cc @@ -48,6 +48,8 @@ /* https://developer.apple.com/documentation/coretext/1508745-ctfontcreatewithgraphicsfont */ #define HB_CORETEXT_DEFAULT_FONT_SIZE 12.f +static CTFontRef create_ct_font (CGFontRef cg_font, CGFloat font_size); + static void release_table_data (void *user_data) { @@ -76,6 +78,52 @@ _hb_cg_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_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 (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) { @@ -287,14 +335,75 @@ _hb_coretext_shaper_face_data_destroy (hb_coretext_face_data_t *data) * Creates an #hb_face_t face object from the specified * CGFontRef. * - * Return value: the new #hb_face_t face object + * Return value: (transfer full): The new face object * * Since: 0.9.10 */ hb_face_t * hb_coretext_face_create (CGFontRef cg_font) { - return hb_face_create_for_tables (_hb_cg_reference_table, CGFontRetain (cg_font), _hb_cg_font_release); + 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); + if (unlikely (hb_face_is_immutable (face))) + return nullptr; + + return face; } /** @@ -347,10 +456,13 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font) hb_ot_var_axis_info_t info; unsigned int c = 1; hb_ot_var_get_axis_infos (font->face, i, &c, &info); - CFDictionarySetValue (variations, - CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &info.tag), - CFNumberCreate (kCFAllocatorDefault, kCFNumberFloatType, &font->design_coords[i]) - ); + 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); + CFDictionarySetValue (variations, tag_number, value_number); + CFRelease (tag_number); + CFRelease (value_number); } CFDictionaryRef attributes = @@ -386,7 +498,12 @@ _hb_coretext_shaper_font_data_destroy (hb_coretext_font_data_t *data) * Creates an #hb_font_t font object from the specified * CTFontRef. * - * Return value: the new #hb_font_t font object + * The created font uses the default font functions implemented + * navitely 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 **/ @@ -407,6 +524,9 @@ hb_coretext_font_create (CTFontRef ct_font) /* 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; } @@ -508,7 +628,6 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, buffer->merge_clusters (i - 1, i + 1); } - hb_vector_t feature_records; hb_vector_t range_records; /* @@ -648,7 +767,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, } else { active_feature_t *feature = active_features.lsearch (event->feature); if (feature) - active_features.remove (feature - active_features.arrayZ); + active_features.remove_ordered (feature - active_features.arrayZ); } } } diff --git a/libs/harfbuzz/src/hb-coretext.h b/libs/harfbuzz/src/hb-coretext.h index e53dbaf2c..3626f1c12 100644 --- a/libs/harfbuzz/src/hb-coretext.h +++ b/libs/harfbuzz/src/hb-coretext.h @@ -44,9 +44,9 @@ HB_BEGIN_DECLS * HB_CORETEXT_TAG_MORT: * * The #hb_tag_t tag for the `mort` (glyph metamorphosis) table, - * which holds AAT features. + * which holds AAT features. * - * For more information, see + * For more information, see * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6mort.html * **/ @@ -56,7 +56,7 @@ HB_BEGIN_DECLS * HB_CORETEXT_TAG_MORX: * * The #hb_tag_t tag for the `morx` (extended glyph metamorphosis) - * table, which holds AAT features. + * table, which holds AAT features. * * For more information, see * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6morx.html @@ -68,9 +68,9 @@ HB_BEGIN_DECLS * HB_CORETEXT_TAG_KERX: * * The #hb_tag_t tag for the `kerx` (extended kerning) table, which - * holds AAT kerning information. + * holds AAT kerning information. * - * For more information, see + * For more information, see * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kerx.html * **/ @@ -80,6 +80,10 @@ HB_BEGIN_DECLS HB_EXTERN hb_face_t * hb_coretext_face_create (CGFontRef cg_font); +HB_EXTERN hb_face_t * +hb_coretext_face_create_from_file_or_fail (const char *file_name, + unsigned int index); + HB_EXTERN hb_font_t * hb_coretext_font_create (CTFontRef ct_font); @@ -90,6 +94,9 @@ hb_coretext_face_get_cg_font (hb_face_t *face); HB_EXTERN CTFontRef hb_coretext_font_get_ct_font (hb_font_t *font); +HB_EXTERN void +hb_coretext_font_set_funcs (hb_font_t *font); + HB_END_DECLS diff --git a/libs/harfbuzz/src/hb-cplusplus.hh b/libs/harfbuzz/src/hb-cplusplus.hh index a210ab796..b6b5c8f78 100644 --- a/libs/harfbuzz/src/hb-cplusplus.hh +++ b/libs/harfbuzz/src/hb-cplusplus.hh @@ -27,9 +27,6 @@ #include "hb.h" -HB_BEGIN_DECLS -HB_END_DECLS - #ifdef __cplusplus #include @@ -56,15 +53,15 @@ struct shared_ptr explicit shared_ptr (T *p = nullptr) : p (p) {} shared_ptr (const shared_ptr &o) : p (v::reference (o.p)) {} - shared_ptr (shared_ptr &&o) : p (o.p) { o.p = nullptr; } + shared_ptr (shared_ptr &&o) noexcept : p (o.p) { o.p = nullptr; } shared_ptr& operator = (const shared_ptr &o) { if (p != o.p) { destroy (); p = o.p; reference (); } return *this; } - shared_ptr& operator = (shared_ptr &&o) { v::destroy (p); p = o.p; o.p = nullptr; return *this; } + shared_ptr& operator = (shared_ptr &&o) noexcept { v::destroy (p); p = o.p; o.p = nullptr; return *this; } ~shared_ptr () { v::destroy (p); p = nullptr; } T* get() const { return p; } - void swap (shared_ptr &o) { std::swap (p, o.p); } - friend void swap (shared_ptr &a, shared_ptr &b) { std::swap (a.p, b.p); } + void swap (shared_ptr &o) noexcept { std::swap (p, o.p); } + friend void swap (shared_ptr &a, shared_ptr &b) noexcept { std::swap (a.p, b.p); } operator T * () const { return p; } T& operator * () const { return *get (); } @@ -98,16 +95,16 @@ struct unique_ptr explicit unique_ptr (T *p = nullptr) : p (p) {} unique_ptr (const unique_ptr &o) = delete; - unique_ptr (unique_ptr &&o) : p (o.p) { o.p = nullptr; } + unique_ptr (unique_ptr &&o) noexcept : p (o.p) { o.p = nullptr; } unique_ptr& operator = (const unique_ptr &o) = delete; - unique_ptr& operator = (unique_ptr &&o) { v::destroy (p); p = o.p; o.p = nullptr; return *this; } + unique_ptr& operator = (unique_ptr &&o) noexcept { v::destroy (p); p = o.p; o.p = nullptr; return *this; } ~unique_ptr () { v::destroy (p); p = nullptr; } T* get() const { return p; } T* release () { T* v = p; p = nullptr; return v; } - void swap (unique_ptr &o) { std::swap (p, o.p); } - friend void swap (unique_ptr &a, unique_ptr &b) { std::swap (a.p, b.p); } + void swap (unique_ptr &o) noexcept { std::swap (p, o.p); } + friend void swap (unique_ptr &a, unique_ptr &b) noexcept { std::swap (a.p, b.p); } operator T * () const { return p; } T& operator * () const { return *get (); } @@ -160,6 +157,8 @@ HB_DEFINE_VTABLE (map); HB_DEFINE_VTABLE (set); HB_DEFINE_VTABLE (shape_plan); HB_DEFINE_VTABLE (unicode_funcs); +HB_DEFINE_VTABLE (draw_funcs); +HB_DEFINE_VTABLE (paint_funcs); #undef HB_DEFINE_VTABLE diff --git a/libs/harfbuzz/src/hb-debug.hh b/libs/harfbuzz/src/hb-debug.hh index cbe13e521..559db4067 100644 --- a/libs/harfbuzz/src/hb-debug.hh +++ b/libs/harfbuzz/src/hb-debug.hh @@ -113,7 +113,7 @@ _hb_print_func (const char *func) const char *paren = strchr (func, '('); if (paren) func_len = paren - func; - fprintf (stderr, "%.*s", func_len, func); + fprintf (stderr, "%.*s", (int) func_len, func); } } @@ -142,9 +142,9 @@ _hb_debug_msg_va (const char *what, fprintf (stderr, "%-10s", what ? what : ""); if (obj) - fprintf (stderr, "(%*p) ", (unsigned int) (2 * sizeof (void *)), obj); + fprintf (stderr, "(%*p) ", (int) (2 * sizeof (void *)), obj); else - fprintf (stderr, " %*s ", (unsigned int) (2 * sizeof (void *)), ""); + fprintf (stderr, " %*s ", (int) (2 * sizeof (void *)), ""); if (indented) { #define VBAR "\342\224\202" /* U+2502 BOX DRAWINGS LIGHT VERTICAL */ @@ -265,8 +265,9 @@ static inline void _hb_warn_no_return (bool returned) } } template <> -/*static*/ inline void _hb_warn_no_return (bool returned HB_UNUSED) -{} +/*static*/ inline void _hb_warn_no_return (bool returned HB_UNUSED) {} +template <> +/*static*/ inline void _hb_warn_no_return (bool returned HB_UNUSED) {} template struct hb_auto_trace_t @@ -306,7 +307,7 @@ struct hb_auto_trace_t } _hb_debug_msg (what, obj, func, true, plevel ? *plevel : 1, -1, - "return %s (line %d)", + "return %s (line %u)", hb_printer_t>().print (v), line); if (plevel) --*plevel; plevel = nullptr; @@ -373,6 +374,10 @@ struct hb_no_trace_t { #define HB_DEBUG_FT (HB_DEBUG+0) #endif +#ifndef HB_DEBUG_JUSTIFY +#define HB_DEBUG_JUSTIFY (HB_DEBUG+0) +#endif + #ifndef HB_DEBUG_OBJECT #define HB_DEBUG_OBJECT (HB_DEBUG+0) #endif @@ -385,6 +390,10 @@ struct hb_no_trace_t { #define HB_DEBUG_UNISCRIBE (HB_DEBUG+0) #endif +#ifndef HB_DEBUG_WASM +#define HB_DEBUG_WASM (HB_DEBUG+0) +#endif + /* * With tracing. */ @@ -396,7 +405,7 @@ struct hb_no_trace_t { #define TRACE_APPLY(this) \ hb_auto_trace_t trace \ (&c->debug_depth, c->get_name (), this, HB_FUNC, \ - "idx %d gid %u lookup %d", \ + "idx %u gid %u lookup %d", \ c->buffer->idx, c->buffer->cur().codepoint, (int) c->lookup_index) #else #define TRACE_APPLY(this) hb_no_trace_t trace @@ -442,19 +451,33 @@ struct hb_no_trace_t { #define HB_DEBUG_SUBSET_REPACK (HB_DEBUG+0) #endif +#ifndef HB_DEBUG_PAINT +#define HB_DEBUG_PAINT (HB_DEBUG+0) +#endif +#if HB_DEBUG_PAINT +#define TRACE_PAINT(this) \ + HB_UNUSED hb_auto_trace_t trace \ + (&c->debug_depth, c->get_name (), this, HB_FUNC, \ + " ") +#else +#define TRACE_PAINT(this) HB_UNUSED hb_no_trace_t trace +#endif + + #ifndef HB_DEBUG_DISPATCH #define HB_DEBUG_DISPATCH ( \ HB_DEBUG_APPLY + \ HB_DEBUG_SANITIZE + \ HB_DEBUG_SERIALIZE + \ HB_DEBUG_SUBSET + \ + HB_DEBUG_PAINT + \ 0) #endif #if HB_DEBUG_DISPATCH #define TRACE_DISPATCH(this, format) \ hb_auto_trace_t trace \ (&c->debug_depth, c->get_name (), this, HB_FUNC, \ - "format %d", (int) format) + "format %u", (unsigned) format) #else #define TRACE_DISPATCH(this, format) hb_no_trace_t trace #endif diff --git a/libs/harfbuzz/src/hb-deprecated.h b/libs/harfbuzz/src/hb-deprecated.h index 333dc3cd4..ad19f9a3e 100644 --- a/libs/harfbuzz/src/hb-deprecated.h +++ b/libs/harfbuzz/src/hb-deprecated.h @@ -56,7 +56,7 @@ HB_BEGIN_DECLS /** * HB_SCRIPT_CANADIAN_ABORIGINAL: * - * Use #HB_SCRIPT_CANADIAN_SYLLABICS instead: + * Use #HB_SCRIPT_CANADIAN_SYLLABICS instead. * * Deprecated: 0.9.20 */ @@ -102,11 +102,22 @@ typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data, hb_codepoint_t *glyph, void *user_data); -HB_EXTERN HB_DEPRECATED_FOR(hb_font_funcs_set_nominal_glyph_func and hb_font_funcs_set_variation_glyph_func) void +HB_DEPRECATED_FOR (hb_font_funcs_set_nominal_glyph_func and hb_font_funcs_set_variation_glyph_func) +HB_EXTERN void hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs, hb_font_get_glyph_func_t func, void *user_data, hb_destroy_func_t destroy); +/* https://github.com/harfbuzz/harfbuzz/pull/4207 */ +/** + * HB_UNICODE_COMBINING_CLASS_CCC133: + * + * [Tibetan] + * + * Deprecated: 7.2.0 + **/ +#define HB_UNICODE_COMBINING_CLASS_CCC133 133 + /** * hb_unicode_eastasian_width_func_t: * @ufuncs: A Unicode-functions structure @@ -244,8 +255,64 @@ HB_EXTERN hb_position_t hb_font_get_glyph_v_kerning (hb_font_t *font, hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph); + +/** + * hb_font_get_glyph_shape_func_t: + * @font: #hb_font_t to work upon + * @font_data: @font user data pointer + * @glyph: The glyph ID to query + * @draw_funcs: The draw functions to send the shape data to + * @draw_data: The data accompanying the draw functions + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * Since: 4.0.0 + * Deprecated: 7.0.0: Use #hb_font_draw_glyph_func_t instead + **/ +typedef void (*hb_font_get_glyph_shape_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, void *draw_data, + void *user_data); + +/** + * hb_font_funcs_set_glyph_shape_func: + * @ffuncs: A font-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore + * + * Sets the implementation function for #hb_font_get_glyph_shape_func_t, + * which is the same as #hb_font_draw_glyph_func_t. + * + * Since: 4.0.0 + * Deprecated: 7.0.0: Use hb_font_funcs_set_draw_glyph_func() instead + **/ +HB_DEPRECATED_FOR (hb_font_funcs_set_draw_glyph_func) +HB_EXTERN void +hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_shape_func_t func, + void *user_data, hb_destroy_func_t destroy); + +HB_DEPRECATED_FOR (hb_font_draw_glyph) +HB_EXTERN void +hb_font_get_glyph_shape (hb_font_t *font, + hb_codepoint_t glyph, + hb_draw_funcs_t *dfuncs, void *draw_data); + + +/** + * HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION: + * + * Use #HB_AAT_LAYOUT_FEATURE_TYPE_CURSIVE_CONNECTION instead. + * + * Deprecated: 8.3.0 + */ +#define HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION HB_AAT_LAYOUT_FEATURE_TYPE_CURSIVE_CONNECTION + #endif + HB_END_DECLS #endif /* HB_DEPRECATED_H */ diff --git a/libs/harfbuzz/src/hb-directwrite.cc b/libs/harfbuzz/src/hb-directwrite.cc index de05b7d87..6c90265d0 100644 --- a/libs/harfbuzz/src/hb-directwrite.cc +++ b/libs/harfbuzz/src/hb-directwrite.cc @@ -173,7 +173,7 @@ _hb_directwrite_shaper_face_data_create (hb_face_t *face) t_DWriteCreateFactory p_DWriteCreateFactory; -#if defined(__GNUC__) +#if defined(__GNUC__) || defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-function-type" #endif @@ -181,7 +181,7 @@ _hb_directwrite_shaper_face_data_create (hb_face_t *face) p_DWriteCreateFactory = (t_DWriteCreateFactory) GetProcAddress (data->dwrite_dll, "DWriteCreateFactory"); -#if defined(__GNUC__) +#if defined(__GNUC__) || defined(__clang__) #pragma GCC diagnostic pop #endif @@ -251,16 +251,12 @@ _hb_directwrite_shaper_face_data_destroy (hb_directwrite_face_data_t *data) data->dwriteFactory->UnregisterFontFileLoader (data->fontFileLoader); data->dwriteFactory->Release (); } - if (data->fontFileLoader) - delete data->fontFileLoader; - if (data->fontFileStream) - delete data->fontFileStream; - if (data->faceBlob) - hb_blob_destroy (data->faceBlob); + delete data->fontFileLoader; + delete data->fontFileStream; + hb_blob_destroy (data->faceBlob); if (data->dwrite_dll) FreeLibrary (data->dwrite_dll); - if (data) - delete data; + delete data; } diff --git a/libs/harfbuzz/src/hb-draw.cc b/libs/harfbuzz/src/hb-draw.cc index 46797e64e..f204f56bc 100644 --- a/libs/harfbuzz/src/hb-draw.cc +++ b/libs/harfbuzz/src/hb-draw.cc @@ -35,6 +35,8 @@ * @include: hb.h * * Functions for drawing (extracting) glyph shapes. + * + * The #hb_draw_funcs_t struct can be used with hb_font_draw_glyph(). **/ static void @@ -80,6 +82,56 @@ hb_draw_close_path_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UN void *user_data HB_UNUSED) {} +static bool +_hb_draw_funcs_set_preamble (hb_draw_funcs_t *dfuncs, + bool func_is_null, + void **user_data, + hb_destroy_func_t *destroy) +{ + if (hb_object_is_immutable (dfuncs)) + { + if (*destroy) + (*destroy) (*user_data); + return false; + } + + if (func_is_null) + { + if (*destroy) + (*destroy) (*user_data); + *destroy = nullptr; + *user_data = nullptr; + } + + return true; +} + +static bool +_hb_draw_funcs_set_middle (hb_draw_funcs_t *dfuncs, + void *user_data, + hb_destroy_func_t destroy) +{ + if (user_data && !dfuncs->user_data) + { + dfuncs->user_data = (decltype (dfuncs->user_data)) hb_calloc (1, sizeof (*dfuncs->user_data)); + if (unlikely (!dfuncs->user_data)) + goto fail; + } + if (destroy && !dfuncs->destroy) + { + dfuncs->destroy = (decltype (dfuncs->destroy)) hb_calloc (1, sizeof (*dfuncs->destroy)); + if (unlikely (!dfuncs->destroy)) + goto fail; + } + + return true; + +fail: + if (destroy) + (destroy) (user_data); + return false; +} + #define HB_DRAW_FUNC_IMPLEMENT(name) \ \ void \ @@ -88,43 +140,24 @@ hb_draw_funcs_set_##name##_func (hb_draw_funcs_t *dfuncs, \ void *user_data, \ hb_destroy_func_t destroy) \ { \ - if (hb_object_is_immutable (dfuncs)) \ - return; \ + if (!_hb_draw_funcs_set_preamble (dfuncs, !func, &user_data, &destroy))\ + return; \ \ if (dfuncs->destroy && dfuncs->destroy->name) \ dfuncs->destroy->name (!dfuncs->user_data ? nullptr : dfuncs->user_data->name); \ \ - if (user_data && !dfuncs->user_data) \ - { \ - dfuncs->user_data = (decltype (dfuncs->user_data)) hb_calloc (1, sizeof (*dfuncs->user_data)); \ - if (unlikely (!dfuncs->user_data)) \ - goto fail; \ - } \ - if (destroy && !dfuncs->destroy) \ - { \ - dfuncs->destroy = (decltype (dfuncs->destroy)) hb_calloc (1, sizeof (*dfuncs->destroy)); \ - if (unlikely (!dfuncs->destroy)) \ - goto fail; \ - } \ + if (!_hb_draw_funcs_set_middle (dfuncs, user_data, destroy)) \ + return; \ \ - if (func) { \ + if (func) \ dfuncs->func.name = func; \ - if (dfuncs->user_data) \ - dfuncs->user_data->name = user_data; \ - if (dfuncs->destroy) \ - dfuncs->destroy->name = destroy; \ - } else { \ + else \ dfuncs->func.name = hb_draw_##name##_nil; \ - if (dfuncs->user_data) \ - dfuncs->user_data->name = nullptr; \ - if (dfuncs->destroy) \ - dfuncs->destroy->name = nullptr; \ - } \ - return; \ - \ -fail: \ - if (destroy) \ - destroy (user_data); \ + \ + if (dfuncs->user_data) \ + dfuncs->user_data->name = user_data; \ + if (dfuncs->destroy) \ + dfuncs->destroy->name = destroy; \ } HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS @@ -167,13 +200,29 @@ DEFINE_NULL_INSTANCE (hb_draw_funcs_t) = } }; +/** + * hb_draw_funcs_get_empty: + * + * Fetches the singleton empty draw-functions structure. + * + * Return value: (transfer full): The empty draw-functions structure + * + * Since: 7.0.0 + **/ +hb_draw_funcs_t * +hb_draw_funcs_get_empty () +{ + return const_cast (&Null (hb_draw_funcs_t)); +} /** * hb_draw_funcs_reference: (skip) * @dfuncs: draw functions * - * Increases the reference count on @dfuncs by one. This prevents @buffer from - * being destroyed until a matching call to hb_draw_funcs_destroy() is made. + * Increases the reference count on @dfuncs by one. + * + * This prevents @dfuncs from being destroyed until a matching + * call to hb_draw_funcs_destroy() is made. * * Return value: (transfer full): * The referenced #hb_draw_funcs_t. @@ -215,6 +264,49 @@ hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs) hb_free (dfuncs); } +/** + * hb_draw_funcs_set_user_data: (skip) + * @dfuncs: The draw-functions structure + * @key: The user-data key + * @data: A pointer to the user data + * @destroy: (nullable): A callback to call when @data is not needed anymore + * @replace: Whether to replace an existing data with the same key + * + * Attaches a user-data key/data pair to the specified draw-functions structure. + * + * Return value: `true` if success, `false` otherwise + * + * Since: 7.0.0 + **/ +hb_bool_t +hb_draw_funcs_set_user_data (hb_draw_funcs_t *dfuncs, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace) +{ + return hb_object_set_user_data (dfuncs, key, data, destroy, replace); +} + +/** + * hb_draw_funcs_get_user_data: (skip) + * @dfuncs: The draw-functions structure + * @key: The user-data key to query + * + * Fetches the user-data associated with the specified key, + * attached to the specified draw-functions structure. + * + * Return value: (transfer none): A pointer to the user data + * + * Since: 7.0.0 + **/ +void * +hb_draw_funcs_get_user_data (const hb_draw_funcs_t *dfuncs, + hb_user_data_key_t *key) +{ + return hb_object_get_user_data (dfuncs, key); +} + /** * hb_draw_funcs_make_immutable: * @dfuncs: draw functions diff --git a/libs/harfbuzz/src/hb-draw.h b/libs/harfbuzz/src/hb-draw.h index c45a53212..6306b69c0 100644 --- a/libs/harfbuzz/src/hb-draw.h +++ b/libs/harfbuzz/src/hb-draw.h @@ -70,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.}, {0.}, {0.}} +#define HB_DRAW_STATE_DEFAULT {0, 0.f, 0.f, 0.f, 0.f, {0.}, {0.}, {0.}, {0.}, {0.}, {0.}, {0.}} /** @@ -92,11 +92,11 @@ typedef struct hb_draw_funcs_t hb_draw_funcs_t; /** * hb_draw_move_to_func_t: * @dfuncs: draw functions object - * @draw_data: The data accompanying the draw functions + * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph() * @st: current draw state * @to_x: X component of target point * @to_y: Y component of target point - * @user_data: User data pointer passed by the caller + * @user_data: User data pointer passed to hb_draw_funcs_set_move_to_func() * * A virtual method for the #hb_draw_funcs_t to perform a "move-to" draw * operation. @@ -112,11 +112,11 @@ typedef void (*hb_draw_move_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data /** * hb_draw_line_to_func_t: * @dfuncs: draw functions object - * @draw_data: The data accompanying the draw functions + * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph() * @st: current draw state * @to_x: X component of target point * @to_y: Y component of target point - * @user_data: User data pointer passed by the caller + * @user_data: User data pointer passed to hb_draw_funcs_set_line_to_func() * * A virtual method for the #hb_draw_funcs_t to perform a "line-to" draw * operation. @@ -132,13 +132,13 @@ typedef void (*hb_draw_line_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data /** * hb_draw_quadratic_to_func_t: * @dfuncs: draw functions object - * @draw_data: The data accompanying the draw functions + * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph() * @st: current draw state * @control_x: X component of control point * @control_y: Y component of control point * @to_x: X component of target point * @to_y: Y component of target point - * @user_data: User data pointer passed by the caller + * @user_data: User data pointer passed to hb_draw_funcs_set_quadratic_to_func() * * A virtual method for the #hb_draw_funcs_t to perform a "quadratic-to" draw * operation. @@ -155,7 +155,7 @@ typedef void (*hb_draw_quadratic_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw /** * hb_draw_cubic_to_func_t: * @dfuncs: draw functions object - * @draw_data: The data accompanying the draw functions + * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph() * @st: current draw state * @control1_x: X component of first control point * @control1_y: Y component of first control point @@ -163,7 +163,7 @@ typedef void (*hb_draw_quadratic_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw * @control2_y: Y component of second control point * @to_x: X component of target point * @to_y: Y component of target point - * @user_data: User data pointer passed by the caller + * @user_data: User data pointer passed to hb_draw_funcs_set_cubic_to_func() * * A virtual method for the #hb_draw_funcs_t to perform a "cubic-to" draw * operation. @@ -181,9 +181,9 @@ typedef void (*hb_draw_cubic_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_dat /** * hb_draw_close_path_func_t: * @dfuncs: draw functions object - * @draw_data: The data accompanying the draw functions + * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph() * @st: current draw state - * @user_data: User data pointer passed by the caller + * @user_data: User data pointer passed to hb_draw_funcs_set_close_path_func() * * A virtual method for the #hb_draw_funcs_t to perform a "close-path" draw * operation. @@ -279,12 +279,27 @@ hb_draw_funcs_set_close_path_func (hb_draw_funcs_t *dfuncs, HB_EXTERN hb_draw_funcs_t * hb_draw_funcs_create (void); +HB_EXTERN hb_draw_funcs_t * +hb_draw_funcs_get_empty (void); + HB_EXTERN hb_draw_funcs_t * hb_draw_funcs_reference (hb_draw_funcs_t *dfuncs); HB_EXTERN void hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs); +HB_EXTERN hb_bool_t +hb_draw_funcs_set_user_data (hb_draw_funcs_t *dfuncs, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace); + + +HB_EXTERN void * +hb_draw_funcs_get_user_data (const hb_draw_funcs_t *dfuncs, + hb_user_data_key_t *key); + HB_EXTERN void hb_draw_funcs_make_immutable (hb_draw_funcs_t *dfuncs); diff --git a/libs/harfbuzz/src/hb-draw.hh b/libs/harfbuzz/src/hb-draw.hh index 768f51a87..87d03a488 100644 --- a/libs/harfbuzz/src/hb-draw.hh +++ b/libs/harfbuzz/src/hb-draw.hh @@ -93,50 +93,57 @@ struct hb_draw_funcs_t !user_data ? nullptr : user_data->close_path); } - void move_to (void *draw_data, hb_draw_state_t &st, - float to_x, float to_y) + void + HB_ALWAYS_INLINE + move_to (void *draw_data, hb_draw_state_t &st, + float to_x, float to_y) { - if (st.path_open) close_path (draw_data, st); + if (unlikely (st.path_open)) close_path (draw_data, st); st.current_x = to_x; st.current_y = to_y; } - void line_to (void *draw_data, hb_draw_state_t &st, - float to_x, float to_y) + void + HB_ALWAYS_INLINE + line_to (void *draw_data, hb_draw_state_t &st, + float to_x, float to_y) { - if (!st.path_open) start_path (draw_data, st); + if (unlikely (!st.path_open)) start_path (draw_data, st); emit_line_to (draw_data, st, to_x, to_y); st.current_x = to_x; st.current_y = to_y; } void + HB_ALWAYS_INLINE quadratic_to (void *draw_data, hb_draw_state_t &st, float control_x, float control_y, float to_x, float to_y) { - if (!st.path_open) start_path (draw_data, st); + if (unlikely (!st.path_open)) start_path (draw_data, st); emit_quadratic_to (draw_data, st, control_x, control_y, to_x, to_y); st.current_x = to_x; st.current_y = to_y; } void + HB_ALWAYS_INLINE cubic_to (void *draw_data, hb_draw_state_t &st, float control1_x, float control1_y, float control2_x, float control2_y, float to_x, float to_y) { - if (!st.path_open) start_path (draw_data, st); + if (unlikely (!st.path_open)) start_path (draw_data, st); 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; } void + HB_ALWAYS_INLINE close_path (void *draw_data, hb_draw_state_t &st) { - if (st.path_open) + if (likely (st.path_open)) { if ((st.path_start_x != st.current_x) || (st.path_start_y != st.current_y)) emit_line_to (draw_data, st, st.path_start_x, st.path_start_y); @@ -168,6 +175,7 @@ struct hb_draw_session_t ~hb_draw_session_t () { close_path (); } + HB_ALWAYS_INLINE void move_to (float to_x, float to_y) { if (likely (not_slanted)) @@ -177,6 +185,7 @@ struct hb_draw_session_t 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) { if (likely (not_slanted)) @@ -187,6 +196,7 @@ struct hb_draw_session_t 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) { @@ -200,6 +210,7 @@ struct hb_draw_session_t to_x + to_y * slant, to_y); } void + HB_ALWAYS_INLINE cubic_to (float control1_x, float control1_y, float control2_x, float control2_y, float to_x, float to_y) @@ -215,12 +226,13 @@ struct hb_draw_session_t control2_x + control2_y * slant, control2_y, to_x + to_y * slant, to_y); } + HB_ALWAYS_INLINE void close_path () { funcs->close_path (draw_data, st); } - protected: + public: float slant; bool not_slanted; hb_draw_funcs_t *funcs; diff --git a/libs/harfbuzz/src/hb-face-builder.cc b/libs/harfbuzz/src/hb-face-builder.cc new file mode 100644 index 000000000..beea89ed2 --- /dev/null +++ b/libs/harfbuzz/src/hb-face-builder.cc @@ -0,0 +1,297 @@ +/* + * Copyright © 2009 Red Hat, Inc. + * Copyright © 2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#include "hb.hh" + +#include "hb-face.hh" + +#include "hb-map.hh" +#include "hb-open-file.hh" +#include "hb-serialize.hh" + + +/* + * face-builder: A face that has add_table(). + */ + +struct face_table_info_t +{ + hb_blob_t* data; + unsigned order; +}; + +struct hb_face_builder_data_t +{ + hb_hashmap_t tables; +}; + +static int compare_entries (const void* pa, const void* pb) +{ + const auto& a = * (const hb_pair_t *) pa; + const auto& b = * (const hb_pair_t *) pb; + + /* Order by blob size first (smallest to largest) and then table tag */ + + if (a.second.order != b.second.order) + return a.second.order < b.second.order ? -1 : +1; + + if (a.second.data->length != b.second.data->length) + return a.second.data->length < b.second.data->length ? -1 : +1; + + return a.first < b.first ? -1 : a.first == b.first ? 0 : +1; +} + +static hb_face_builder_data_t * +_hb_face_builder_data_create () +{ + hb_face_builder_data_t *data = (hb_face_builder_data_t *) hb_calloc (1, sizeof (hb_face_builder_data_t)); + if (unlikely (!data)) + return nullptr; + + data->tables.init (); + + return data; +} + +static void +_hb_face_builder_data_destroy (void *user_data) +{ + hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data; + + for (auto info : data->tables.values()) + hb_blob_destroy (info.data); + + data->tables.fini (); + + hb_free (data); +} + +static hb_blob_t * +_hb_face_builder_data_reference_blob (hb_face_builder_data_t *data) +{ + + unsigned int table_count = data->tables.get_population (); + unsigned int face_length = table_count * 16 + 12; + + for (auto info : data->tables.values()) + face_length += hb_ceil_to_4 (hb_blob_get_length (info.data)); + + char *buf = (char *) hb_malloc (face_length); + if (unlikely (!buf)) + return nullptr; + + hb_serialize_context_t c (buf, face_length); + c.propagate_error (data->tables); + OT::OpenTypeFontFile *f = c.start_serialize (); + + bool is_cff = (data->tables.has (HB_TAG ('C','F','F',' ')) + || data->tables.has (HB_TAG ('C','F','F','2'))); + hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag; + + // Sort the tags so that produced face is deterministic. + hb_vector_t> sorted_entries; + data->tables.iter () | hb_sink (sorted_entries); + if (unlikely (sorted_entries.in_error ())) + { + hb_free (buf); + return nullptr; + } + + sorted_entries.qsort (compare_entries); + + bool ret = f->serialize_single (&c, + sfnt_tag, + + sorted_entries.iter() + | hb_map ([&] (hb_pair_t _) { + return hb_pair_t (_.first, _.second.data); + })); + + c.end_serialize (); + + if (unlikely (!ret)) + { + hb_free (buf); + return nullptr; + } + + return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, hb_free); +} + +static hb_blob_t * +_hb_face_builder_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) +{ + hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data; + + if (!tag) + return _hb_face_builder_data_reference_blob (data); + + return hb_blob_reference (data->tables[tag].data); +} + +static unsigned +_hb_face_builder_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) +{ + hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data; + + unsigned population = data->tables.get_population (); + + if (!table_count) + return population; + + if (unlikely (start_offset >= population)) + { + if (table_count) + *table_count = 0; + return population; + } + + // Sort the tags. + hb_vector_t sorted_tags; + data->tables.keys () | hb_sink (sorted_tags); + if (unlikely (sorted_tags.in_error ())) + { + // Not much to do... + } + sorted_tags.qsort ([] (const void* a, const void* b) { + return * (hb_tag_t *) a < * (hb_tag_t *) b ? -1 : + * (hb_tag_t *) a == * (hb_tag_t *) b ? 0 : + +1; + }); + + auto array = sorted_tags.as_array ().sub_array (start_offset, table_count); + auto out = hb_array (table_tags, *table_count); + + + array.iter () + | hb_sink (out) + ; + + return population; +} + + +/** + * hb_face_builder_create: + * + * Creates a #hb_face_t that can be used with hb_face_builder_add_table(). + * After tables are added to the face, it can be compiled to a binary + * font file by calling hb_face_reference_blob(). + * + * Return value: (transfer full): New face. + * + * Since: 1.9.0 + **/ +hb_face_t * +hb_face_builder_create () +{ + hb_face_builder_data_t *data = _hb_face_builder_data_create (); + if (unlikely (!data)) return hb_face_get_empty (); + + hb_face_t *face = hb_face_create_for_tables (_hb_face_builder_reference_table, + data, + _hb_face_builder_data_destroy); + + hb_face_set_get_table_tags_func (face, + _hb_face_builder_get_table_tags, + data, + nullptr); + + return face; +} + +/** + * hb_face_builder_add_table: + * @face: A face object created with hb_face_builder_create() + * @tag: The #hb_tag_t of the table to add + * @blob: The blob containing the table data to add + * + * Add table for @tag with data provided by @blob to the face. @face must + * be created using hb_face_builder_create(). + * + * Since: 1.9.0 + **/ +hb_bool_t +hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob) +{ + if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy)) + return false; + + if (tag == HB_MAP_VALUE_INVALID) + return false; + + hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data; + + hb_blob_t* previous = data->tables.get (tag).data; + if (!data->tables.set (tag, face_table_info_t {hb_blob_reference (blob), (unsigned) -1})) + { + hb_blob_destroy (blob); + return false; + } + + hb_blob_destroy (previous); + return true; +} + +/** + * hb_face_builder_sort_tables: + * @face: A face object created with hb_face_builder_create() + * @tags: (array zero-terminated=1): ordered list of table tags terminated by + * %HB_TAG_NONE + * + * Set the ordering of tables for serialization. Any tables not + * specified in the tags list will be ordered after the tables in + * tags, ordered by the default sort ordering. + * + * Since: 5.3.0 + **/ +void +hb_face_builder_sort_tables (hb_face_t *face, + const hb_tag_t *tags) +{ + if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy)) + return; + + hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data; + + // Sort all unspecified tables after any specified tables. + for (auto& info : data->tables.values_ref()) + info.order = (unsigned) -1; + + signed order = 0; + for (const hb_tag_t* tag = tags; + *tag; + tag++) + { + face_table_info_t* info; + if (!data->tables.has (*tag, &info)) continue; + info->order = order++; + } +} diff --git a/libs/harfbuzz/src/hb-face.cc b/libs/harfbuzz/src/hb-face.cc index e7deb31dd..bc0f6d90d 100644 --- a/libs/harfbuzz/src/hb-face.cc +++ b/libs/harfbuzz/src/hb-face.cc @@ -33,7 +33,6 @@ #include "hb-open-file.hh" #include "hb-ot-face.hh" #include "hb-ot-cmap-table.hh" -#include "hb-map.hh" /** @@ -48,6 +47,12 @@ * More precisely, a font face represents a single face in a binary font file. * Font faces are typically built from a binary blob and a face index. * Font faces are used to create fonts. + * + * A font face can be created from a binary blob using hb_face_create(). + * The face index is used to select a face from a binary blob that contains + * multiple faces. For example, a binary blob that contains both a regular + * and a bold face can be used to create two font faces, one for each face + * index. **/ @@ -85,10 +90,6 @@ DEFINE_NULL_INSTANCE (hb_face_t) = { HB_OBJECT_HEADER_STATIC, - nullptr, /* reference_table_func */ - nullptr, /* user_data */ - nullptr, /* destroy */ - 0, /* index */ 1000, /* upem */ 0, /* num_glyphs */ @@ -105,8 +106,9 @@ DEFINE_NULL_INSTANCE (hb_face_t) = * * Variant of hb_face_create(), built for those cases where it is more * convenient to provide data for individual tables instead of the whole font - * data. With the caveat that hb_face_get_table_tags() does not currently work - * with faces created this way. + * data. With the caveat that hb_face_get_table_tags() would not work + * with faces created this way. You can address that by calling the + * hb_face_set_get_table_tags_func() function and setting the appropriate callback. * * Creates a new face object from the specified @user_data and @reference_table_func, * with the @destroy callback. @@ -189,6 +191,22 @@ _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void return blob; } +static unsigned +_hb_face_for_data_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) +{ + hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) user_data; + + const OT::OpenTypeFontFile &ot_file = *data->blob->as (); + const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index); + + return ot_face.get_table_tags (start_offset, table_count, table_tags); +} + + /** * hb_face_create: * @blob: #hb_blob_t to work upon @@ -198,7 +216,7 @@ _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void * a face index into that blob. * * The face index is used for blobs of file formats such as TTC and - * and DFont that can contain more than one face. Face indices within + * DFont that can contain more than one face. Face indices within * such collections are zero-based. * * Note: If the blob font format is not a collection, @index @@ -235,12 +253,71 @@ hb_face_create (hb_blob_t *blob, face = hb_face_create_for_tables (_hb_face_for_data_reference_table, closure, _hb_face_for_data_closure_destroy); + hb_face_set_get_table_tags_func (face, + _hb_face_for_data_get_table_tags, + closure, + nullptr); face->index = index; return face; } +/** + * hb_face_create_or_fail: + * @blob: #hb_blob_t to work upon + * @index: The index of the face within @blob + * + * Like hb_face_create(), but returns `NULL` if the blob data + * contains no usable font face at the specified index. + * + * Return value: (transfer full): The new face object, or `NULL` if + * no face is found at the specified index. + * + * Since: 10.1.0 + **/ +hb_face_t * +hb_face_create_or_fail (hb_blob_t *blob, + unsigned int index) +{ + unsigned num_faces = hb_face_count (blob); + if (index >= num_faces) + return nullptr; + + hb_face_t *face = hb_face_create (blob, index); + if (hb_object_is_immutable (face)) + return nullptr; + + return face; +} + +/** + * hb_face_create_from_file_or_fail: + * @file_name: A font filename + * @index: The index of the face within the file + * + * A thin wrapper around hb_blob_create_from_file_or_fail() + * followed by hb_face_create_or_fail(). + * + * 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_EXTERN hb_face_t * +hb_face_create_from_file_or_fail (const char *file_name, + unsigned int index) +{ + hb_blob_t *blob = hb_blob_create_from_file_or_fail (file_name); + if (unlikely (!blob)) + return nullptr; + + hb_face_t *face = hb_face_create_or_fail (blob, index); + hb_blob_destroy (blob); + + return face; +} + /** * hb_face_get_empty: * @@ -288,6 +365,7 @@ hb_face_destroy (hb_face_t *face) { if (!hb_object_destroy (face)) return; +#ifndef HB_NO_SHAPER for (hb_face_t::plan_node_t *node = face->shape_plans; node; ) { hb_face_t::plan_node_t *next = node->next; @@ -295,10 +373,14 @@ hb_face_destroy (hb_face_t *face) hb_free (node); node = next; } +#endif face->data.fini (); face->table.fini (); + if (face->get_table_tags_destroy) + face->get_table_tags_destroy (face->get_table_tags_user_data); + if (face->destroy) face->destroy (face->user_data); @@ -470,6 +552,8 @@ hb_face_get_index (const hb_face_t *face) * * Sets the units-per-em (upem) for a face object to the specified value. * + * This API is used in rare circumstances. + * * Since: 0.9.2 **/ void @@ -486,7 +570,10 @@ hb_face_set_upem (hb_face_t *face, * hb_face_get_upem: * @face: A face object * - * Fetches the units-per-em (upem) value of the specified face object. + * Fetches the units-per-em (UPEM) value of the specified face object. + * + * Typical UPEM values for fonts are 1000, or 2048, but any value + * in between 16 and 16,384 is allowed for OpenType fonts. * * Return value: The upem value of @face * @@ -505,6 +592,8 @@ hb_face_get_upem (const hb_face_t *face) * * Sets the glyph count for a face object to the specified value. * + * This API is used in rare circumstances. + * * Since: 0.9.7 **/ void @@ -533,6 +622,37 @@ hb_face_get_glyph_count (const hb_face_t *face) return face->get_num_glyphs (); } +/** + * hb_face_set_get_table_tags_func: + * @face: A face object + * @func: (closure user_data) (destroy destroy) (scope notified): The table-tag-fetching function + * @user_data: A pointer to the user data, to be destroyed by @destroy when not needed anymore + * @destroy: (nullable): A callback to call when @func is not needed anymore + * + * Sets the table-tag-fetching function for the specified face object. + * + * Since: 10.0.0 + */ +HB_EXTERN void +hb_face_set_get_table_tags_func (hb_face_t *face, + hb_get_table_tags_func_t func, + void *user_data, + hb_destroy_func_t destroy) +{ + if (hb_object_is_immutable (face)) + { + if (destroy) + destroy (user_data); + } + + if (face->get_table_tags_destroy) + face->get_table_tags_destroy (face->get_table_tags_user_data); + + face->get_table_tags_func = func; + face->get_table_tags_user_data = user_data; + face->get_table_tags_destroy = destroy; +} + /** * hb_face_get_table_tags: * @face: A face object @@ -554,19 +674,14 @@ hb_face_get_table_tags (const hb_face_t *face, unsigned int *table_count, /* IN/OUT */ hb_tag_t *table_tags /* OUT */) { - if (face->destroy != (hb_destroy_func_t) _hb_face_for_data_closure_destroy) + if (!face->get_table_tags_func) { if (table_count) *table_count = 0; return 0; } - hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) face->user_data; - - const OT::OpenTypeFontFile &ot_file = *data->blob->as (); - const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index); - - return ot_face.get_table_tags (start_offset, table_count, table_tags); + return face->get_table_tags_func (face, start_offset, table_count, table_tags, face->get_table_tags_user_data); } @@ -579,7 +694,7 @@ hb_face_get_table_tags (const hb_face_t *face, /** * hb_face_collect_unicodes: * @face: A face object - * @out: The set to add Unicode characters to + * @out: (out): The set to add Unicode characters to * * Collects all of the Unicode characters covered by @face and adds * them to the #hb_set_t set @out. @@ -592,10 +707,31 @@ hb_face_collect_unicodes (hb_face_t *face, { face->table.cmap->collect_unicodes (out, face->get_num_glyphs ()); } +/** + * hb_face_collect_nominal_glyph_mapping: + * @face: A face object + * @mapping: (out): The map to add Unicode-to-glyph mapping to + * @unicodes: (nullable) (out): The set to add Unicode characters to, or `NULL` + * + * Collects the mapping from Unicode characters to nominal glyphs of the @face, + * and optionally all of the Unicode characters covered by @face. + * + * Since: 7.0.0 + */ +void +hb_face_collect_nominal_glyph_mapping (hb_face_t *face, + hb_map_t *mapping, + hb_set_t *unicodes) +{ + hb_set_t stack_unicodes; + if (!unicodes) + unicodes = &stack_unicodes; + face->table.cmap->collect_mapping (unicodes, mapping, face->get_num_glyphs ()); +} /** * hb_face_collect_variation_selectors: * @face: A face object - * @out: The set to add Variation Selector characters to + * @out: (out): The set to add Variation Selector characters to * * Collects all Unicode "Variation Selector" characters covered by @face and adds * them to the #hb_set_t set @out. @@ -612,7 +748,7 @@ hb_face_collect_variation_selectors (hb_face_t *face, * hb_face_collect_variation_unicodes: * @face: A face object * @variation_selector: The Variation Selector to query - * @out: The set to add Unicode characters to + * @out: (out): The set to add Unicode characters to * * Collects all Unicode characters for @variation_selector covered by @face and adds * them to the #hb_set_t set @out. @@ -627,211 +763,3 @@ hb_face_collect_variation_unicodes (hb_face_t *face, face->table.cmap->collect_variation_unicodes (variation_selector, out); } #endif - - -/* - * face-builder: A face that has add_table(). - */ - -struct face_table_info_t -{ - hb_blob_t* data; - unsigned order; -}; - -struct hb_face_builder_data_t -{ - hb_hashmap_t tables; -}; - -static int compare_entries (const void* pa, const void* pb) -{ - const auto& a = * (const hb_pair_t *) pa; - const auto& b = * (const hb_pair_t *) pb; - - /* Order by blob size first (smallest to largest) and then table tag */ - - if (a.second.order != b.second.order) - return a.second.order < b.second.order ? -1 : +1; - - if (a.second.data->length != b.second.data->length) - return a.second.data->length < b.second.data->length ? -1 : +1; - - return a.first < b.first ? -1 : a.first == b.first ? 0 : +1; -} - -static hb_face_builder_data_t * -_hb_face_builder_data_create () -{ - hb_face_builder_data_t *data = (hb_face_builder_data_t *) hb_calloc (1, sizeof (hb_face_builder_data_t)); - if (unlikely (!data)) - return nullptr; - - data->tables.init (); - - return data; -} - -static void -_hb_face_builder_data_destroy (void *user_data) -{ - hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data; - - for (auto info : data->tables.values()) - hb_blob_destroy (info.data); - - data->tables.fini (); - - hb_free (data); -} - -static hb_blob_t * -_hb_face_builder_data_reference_blob (hb_face_builder_data_t *data) -{ - - unsigned int table_count = data->tables.get_population (); - unsigned int face_length = table_count * 16 + 12; - - for (auto info : data->tables.values()) - face_length += hb_ceil_to_4 (hb_blob_get_length (info.data)); - - char *buf = (char *) hb_malloc (face_length); - if (unlikely (!buf)) - return nullptr; - - hb_serialize_context_t c (buf, face_length); - c.propagate_error (data->tables); - OT::OpenTypeFontFile *f = c.start_serialize (); - - bool is_cff = (data->tables.has (HB_TAG ('C','F','F',' ')) - || data->tables.has (HB_TAG ('C','F','F','2'))); - hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag; - - // Sort the tags so that produced face is deterministic. - hb_vector_t> sorted_entries; - data->tables.iter () | hb_sink (sorted_entries); - if (unlikely (sorted_entries.in_error ())) - { - hb_free (buf); - return nullptr; - } - - sorted_entries.qsort (compare_entries); - - bool ret = f->serialize_single (&c, - sfnt_tag, - + sorted_entries.iter() - | hb_map ([&] (hb_pair_t _) { - return hb_pair_t (_.first, _.second.data); - })); - - c.end_serialize (); - - if (unlikely (!ret)) - { - hb_free (buf); - return nullptr; - } - - return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, hb_free); -} - -static hb_blob_t * -_hb_face_builder_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) -{ - hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data; - - if (!tag) - return _hb_face_builder_data_reference_blob (data); - - return hb_blob_reference (data->tables[tag].data); -} - - -/** - * hb_face_builder_create: - * - * Creates a #hb_face_t that can be used with hb_face_builder_add_table(). - * After tables are added to the face, it can be compiled to a binary - * font file by calling hb_face_reference_blob(). - * - * Return value: (transfer full): New face. - * - * Since: 1.9.0 - **/ -hb_face_t * -hb_face_builder_create () -{ - hb_face_builder_data_t *data = _hb_face_builder_data_create (); - if (unlikely (!data)) return hb_face_get_empty (); - - return hb_face_create_for_tables (_hb_face_builder_reference_table, - data, - _hb_face_builder_data_destroy); -} - -/** - * hb_face_builder_add_table: - * @face: A face object created with hb_face_builder_create() - * @tag: The #hb_tag_t of the table to add - * @blob: The blob containing the table data to add - * - * Add table for @tag with data provided by @blob to the face. @face must - * be created using hb_face_builder_create(). - * - * Since: 1.9.0 - **/ -hb_bool_t -hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob) -{ - if (tag == HB_MAP_VALUE_INVALID) - return false; - - if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy)) - return false; - - hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data; - - hb_blob_t* previous = data->tables.get (tag).data; - if (!data->tables.set (tag, face_table_info_t {hb_blob_reference (blob), 0})) - { - hb_blob_destroy (blob); - return false; - } - - hb_blob_destroy (previous); - return true; -} - -/** - * hb_face_builder_sort_tables: - * @face: A face object created with hb_face_builder_create() - * @tags: (array zero-terminated=1): ordered list of table tags terminated by - * %HB_TAG_NONE - * - * Set the ordering of tables for serialization. Any tables not - * specified in the tags list will be ordered after the tables in - * tags, ordered by the default sort ordering. - * - * Since: 5.3.0 - **/ -void -hb_face_builder_sort_tables (hb_face_t *face, - const hb_tag_t *tags) -{ - hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data; - - // Sort all unspecified tables after any specified tables. - for (auto& info : data->tables.values_ref()) - info.order = -1; - - unsigned order = 0; - for (const hb_tag_t* tag = tags; - *tag; - tag++) - { - face_table_info_t* info; - if (!data->tables.has (*tag, &info)) continue; - info->order = order++; - } -} diff --git a/libs/harfbuzz/src/hb-face.h b/libs/harfbuzz/src/hb-face.h index 38e7104af..8aec681cf 100644 --- a/libs/harfbuzz/src/hb-face.h +++ b/libs/harfbuzz/src/hb-face.h @@ -33,6 +33,7 @@ #include "hb-common.h" #include "hb-blob.h" +#include "hb-map.h" #include "hb-set.h" HB_BEGIN_DECLS @@ -58,6 +59,14 @@ HB_EXTERN hb_face_t * hb_face_create (hb_blob_t *blob, unsigned int index); +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_from_file_or_fail (const char *file_name, + unsigned int index); + /** * hb_reference_table_func_t: * @face: an #hb_face_t to reference table for @@ -134,6 +143,34 @@ hb_face_set_glyph_count (hb_face_t *face, HB_EXTERN unsigned int hb_face_get_glyph_count (const hb_face_t *face); + +/** + * hb_get_table_tags_func_t: + * @face: A face object + * @start_offset: The index of first table tag to retrieve + * @table_count: (inout): Input = the maximum number of table tags to return; + * Output = the actual number of table tags returned (may be zero) + * @table_tags: (out) (array length=table_count): The array of table tags found + * @user_data: User data pointer passed by the caller + * + * Callback function for hb_face_get_table_tags(). + * + * Return value: Total number of tables, or zero if it is not possible to list + * + * Since: 10.0.0 + */ +typedef unsigned int (*hb_get_table_tags_func_t) (const hb_face_t *face, + unsigned int start_offset, + unsigned int *table_count, /* IN/OUT */ + hb_tag_t *table_tags /* OUT */, + void *user_data); + +HB_EXTERN void +hb_face_set_get_table_tags_func (hb_face_t *face, + hb_get_table_tags_func_t func, + void *user_data, + hb_destroy_func_t destroy); + HB_EXTERN unsigned int hb_face_get_table_tags (const hb_face_t *face, unsigned int start_offset, @@ -149,6 +186,11 @@ HB_EXTERN void hb_face_collect_unicodes (hb_face_t *face, hb_set_t *out); +HB_EXTERN void +hb_face_collect_nominal_glyph_mapping (hb_face_t *face, + hb_map_t *mapping, + hb_set_t *unicodes); + HB_EXTERN void hb_face_collect_variation_selectors (hb_face_t *face, hb_set_t *out); diff --git a/libs/harfbuzz/src/hb-face.hh b/libs/harfbuzz/src/hb-face.hh index 12e10d01e..640156832 100644 --- a/libs/harfbuzz/src/hb-face.hh +++ b/libs/harfbuzz/src/hb-face.hh @@ -48,13 +48,17 @@ struct hb_face_t { hb_object_header_t header; + unsigned int index; /* Face index in a collection, zero-based. */ + mutable hb_atomic_int_t upem; /* Units-per-EM. */ + mutable hb_atomic_int_t num_glyphs; /* Number of glyphs. */ + hb_reference_table_func_t reference_table_func; void *user_data; hb_destroy_func_t destroy; - unsigned int index; /* Face index in a collection, zero-based. */ - mutable hb_atomic_int_t upem; /* Units-per-EM. */ - mutable hb_atomic_int_t num_glyphs; /* Number of glyphs. */ + hb_get_table_tags_func_t get_table_tags_func; + void *get_table_tags_user_data; + hb_destroy_func_t get_table_tags_destroy; hb_shaper_object_dataset_t data;/* Various shaper data. */ hb_ot_face_t table; /* All the face's tables. */ @@ -65,7 +69,9 @@ struct hb_face_t hb_shape_plan_t *shape_plan; plan_node_t *next; }; +#ifndef HB_NO_SHAPER hb_atomic_ptr_t shape_plans; +#endif hb_blob_t *reference_table (hb_tag_t tag) const { @@ -74,7 +80,7 @@ struct hb_face_t if (unlikely (!reference_table_func)) return hb_blob_get_empty (); - blob = reference_table_func (/*XXX*/const_cast (this), tag, user_data); + blob = reference_table_func (/*Oh, well.*/const_cast (this), tag, user_data); if (unlikely (!blob)) return hb_blob_get_empty (); diff --git a/libs/harfbuzz/src/hb-fallback-shape.cc b/libs/harfbuzz/src/hb-fallback-shape.cc index f8524ecc8..c54ad8764 100644 --- a/libs/harfbuzz/src/hb-fallback-shape.cc +++ b/libs/harfbuzz/src/hb-fallback-shape.cc @@ -75,16 +75,6 @@ _hb_fallback_shape (hb_shape_plan_t *shape_plan HB_UNUSED, const hb_feature_t *features HB_UNUSED, unsigned int num_features HB_UNUSED) { - /* TODO - * - * - Apply fallback kern. - * - Handle Variation Selectors? - * - Apply normalization? - * - * This will make the fallback shaper into a dumb "TrueType" - * shaper which many people unfortunately still request. - */ - hb_codepoint_t space; bool has_space = (bool) font->get_nominal_glyph (' ', &space); diff --git a/libs/harfbuzz/src/hb-features.h.in b/libs/harfbuzz/src/hb-features.h.in new file mode 100644 index 000000000..4b27bd5e7 --- /dev/null +++ b/libs/harfbuzz/src/hb-features.h.in @@ -0,0 +1,119 @@ +/* + * Copyright © 2022 Red Hat, 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. + */ + +#ifndef HB_FEATURES_H +#define HB_FEATURES_H + +HB_BEGIN_DECLS + +/** + * SECTION: hb-features + * @title: hb-features + * @short_description: Feature detection + * @include: hb-features.h + * + * Macros for detecting optional HarfBuzz features at build time. + **/ + +/** + * HB_HAS_CAIRO: + * + * Defined if Harfbuzz has been built with cairo support. + */ +#mesondefine HB_HAS_CAIRO + +/** + * HB_HAS_CORETEXT: + * + * Defined if Harfbuzz has been built with CoreText support. + */ +#mesondefine HB_HAS_CORETEXT + +/** + * HB_HAS_DIRECTWRITE: + * + * Defined if Harfbuzz has been built with DirectWrite support. + */ +#mesondefine HB_HAS_DIRECTWRITE + +/** + * HB_HAS_FREETYPE: + * + * Defined if Harfbuzz has been built with Freetype support. + */ +#mesondefine HB_HAS_FREETYPE + +/** + * HB_HAS_GDI: + * + * Defined if Harfbuzz has been built with GDI support. + */ +#mesondefine HB_HAS_GDI + +/** + * HB_HAS_GLIB: + * + * Defined if Harfbuzz has been built with GLib support. + */ +#mesondefine HB_HAS_GLIB + +/** + * HB_HAS_GOBJECT: + * + * Defined if Harfbuzz has been built with GObject support. + */ +#mesondefine HB_HAS_GOBJECT + +/** + * HB_HAS_GRAPHITE: + * + * Defined if Harfbuzz has been built with Graphite support. + */ +#mesondefine HB_HAS_GRAPHITE + +/** + * HB_HAS_ICU: + * + * Defined if Harfbuzz has been built with ICU support. + */ +#mesondefine HB_HAS_ICU + +/** + * HB_HAS_UNISCRIBE: + * + * Defined if Harfbuzz has been built with Uniscribe support. + */ +#mesondefine HB_HAS_UNISCRIBE + +/** + * HB_HAS_WASM: + * + * Defined if Harfbuzz has been built with WebAssembly support. + */ +#mesondefine HB_HAS_WASM + + +HB_END_DECLS + +#endif /* HB_FEATURES_H */ diff --git a/libs/harfbuzz/src/hb-font.cc b/libs/harfbuzz/src/hb-font.cc index 856bbdda3..96b79ecca 100644 --- a/libs/harfbuzz/src/hb-font.cc +++ b/libs/harfbuzz/src/hb-font.cc @@ -30,6 +30,7 @@ #include "hb-font.hh" #include "hb-draw.hh" +#include "hb-paint.hh" #include "hb-machinery.hh" #include "hb-ot.h" @@ -58,6 +59,11 @@ * * HarfBuzz provides a built-in set of lightweight default * functions for each method in #hb_font_funcs_t. + * + * The default font functions are implemented in terms of the + * #hb_font_funcs_t methods of the parent font object. This allows + * client programs to override only the methods they need to, and + * otherwise inherit the parent font's implementation, if any. **/ @@ -71,7 +77,7 @@ hb_font_get_font_h_extents_nil (hb_font_t *font HB_UNUSED, hb_font_extents_t *extents, void *user_data HB_UNUSED) { - memset (extents, 0, sizeof (*extents)); + hb_memset (extents, 0, sizeof (*extents)); return false; } @@ -96,7 +102,7 @@ hb_font_get_font_v_extents_nil (hb_font_t *font HB_UNUSED, hb_font_extents_t *extents, void *user_data HB_UNUSED) { - memset (extents, 0, sizeof (*extents)); + hb_memset (extents, 0, sizeof (*extents)); return false; } @@ -225,7 +231,7 @@ hb_font_get_glyph_v_advance_nil (hb_font_t *font, void *user_data HB_UNUSED) { /* TODO use font_extents.ascender+descender */ - return font->y_scale; + return -font->y_scale; } static hb_position_t @@ -409,7 +415,7 @@ hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED, hb_glyph_extents_t *extents, void *user_data HB_UNUSED) { - memset (extents, 0, sizeof (*extents)); + hb_memset (extents, 0, sizeof (*extents)); return false; } @@ -503,22 +509,34 @@ hb_font_get_glyph_from_name_default (hb_font_t *font, } static void -hb_font_get_glyph_shape_nil (hb_font_t *font HB_UNUSED, - void *font_data HB_UNUSED, - hb_codepoint_t glyph, - hb_draw_funcs_t *draw_funcs, - void *draw_data, - void *user_data HB_UNUSED) +hb_font_draw_glyph_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, + void *draw_data, + void *user_data HB_UNUSED) { } +static void +hb_font_paint_glyph_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph HB_UNUSED, + hb_paint_funcs_t *paint_funcs HB_UNUSED, + void *paint_data HB_UNUSED, + unsigned int palette HB_UNUSED, + hb_color_t foreground HB_UNUSED, + void *user_data HB_UNUSED) +{ +} -typedef struct hb_font_get_glyph_shape_default_adaptor_t { +typedef struct hb_font_draw_glyph_default_adaptor_t { hb_draw_funcs_t *draw_funcs; void *draw_data; float x_scale; float y_scale; -} hb_font_get_glyph_shape_default_adaptor_t; + float slant; +} hb_font_draw_glyph_default_adaptor_t; static void hb_draw_move_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, @@ -527,12 +545,13 @@ hb_draw_move_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, float to_x, float to_y, void *user_data HB_UNUSED) { - hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data; + hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data; float x_scale = adaptor->x_scale; float y_scale = adaptor->y_scale; + float slant = adaptor->slant; adaptor->draw_funcs->emit_move_to (adaptor->draw_data, *st, - x_scale * to_x, y_scale * to_y); + x_scale * to_x + slant * to_y, y_scale * to_y); } static void @@ -541,15 +560,16 @@ hb_draw_line_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data, float to_x, float to_y, void *user_data HB_UNUSED) { - hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data; + hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data; float x_scale = adaptor->x_scale; float y_scale = adaptor->y_scale; + float slant = adaptor->slant; - st->current_x *= x_scale; - st->current_y *= y_scale; + st->current_x = st->current_x * x_scale + st->current_y * slant; + st->current_y = st->current_y * y_scale; adaptor->draw_funcs->emit_line_to (adaptor->draw_data, *st, - x_scale * to_x, y_scale * to_y); + x_scale * to_x + slant * to_y, y_scale * to_y); } static void @@ -559,16 +579,17 @@ hb_draw_quadratic_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data float to_x, float to_y, void *user_data HB_UNUSED) { - hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data; + hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data; float x_scale = adaptor->x_scale; float y_scale = adaptor->y_scale; + float slant = adaptor->slant; - st->current_x *= x_scale; - st->current_y *= y_scale; + st->current_x = st->current_x * x_scale + st->current_y * slant; + st->current_y = st->current_y * y_scale; adaptor->draw_funcs->emit_quadratic_to (adaptor->draw_data, *st, - x_scale * control_x, y_scale * control_y, - x_scale * to_x, y_scale * to_y); + x_scale * control_x + slant * control_y, y_scale * control_y, + x_scale * to_x + slant * to_y, y_scale * to_y); } static void @@ -579,17 +600,18 @@ hb_draw_cubic_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data, float to_x, float to_y, void *user_data HB_UNUSED) { - hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data; + hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data; float x_scale = adaptor->x_scale; float y_scale = adaptor->y_scale; + float slant = adaptor->slant; - st->current_x *= x_scale; - st->current_y *= y_scale; + st->current_x = st->current_x * x_scale + st->current_y * slant; + st->current_y = st->current_y * y_scale; adaptor->draw_funcs->emit_cubic_to (adaptor->draw_data, *st, - x_scale * control1_x, y_scale * control1_y, - x_scale * control2_x, y_scale * control2_y, - x_scale * to_x, y_scale * to_y); + x_scale * control1_x + slant * control1_y, y_scale * control1_y, + x_scale * control2_x + slant * control2_y, y_scale * control2_y, + x_scale * to_x + slant * to_y, y_scale * to_y); } static void @@ -597,7 +619,7 @@ hb_draw_close_path_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data, hb_draw_state_t *st, void *user_data HB_UNUSED) { - hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data; + hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data; adaptor->draw_funcs->emit_close_path (adaptor->draw_data, *st); } @@ -613,25 +635,50 @@ static const hb_draw_funcs_t _hb_draw_funcs_default = { }; static void -hb_font_get_glyph_shape_default (hb_font_t *font, +hb_font_draw_glyph_default (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 HB_UNUSED) { - hb_font_get_glyph_shape_default_adaptor_t adaptor = { + hb_font_draw_glyph_default_adaptor_t adaptor = { draw_funcs, draw_data, - (float) font->x_scale / (float) font->parent->x_scale, - (float) font->y_scale / (float) font->parent->y_scale + font->parent->x_scale ? (float) font->x_scale / (float) font->parent->x_scale : 0.f, + font->parent->y_scale ? (float) font->y_scale / (float) font->parent->y_scale : 0.f, + font->parent->y_scale ? (font->slant - font->parent->slant) * + (float) font->x_scale / (float) font->parent->y_scale : 0.f }; - font->parent->get_glyph_shape (glyph, + font->parent->draw_glyph (glyph, const_cast (&_hb_draw_funcs_default), &adaptor); } +static void +hb_font_paint_glyph_default (hb_font_t *font, + void *font_data, + hb_codepoint_t glyph, + hb_paint_funcs_t *paint_funcs, + void *paint_data, + unsigned int palette, + hb_color_t foreground, + void *user_data) +{ + paint_funcs->push_transform (paint_data, + font->parent->x_scale ? (float) font->x_scale / (float) font->parent->x_scale : 0.f, + font->parent->y_scale ? (font->slant - font->parent->slant) * + (float) font->x_scale / (float) font->parent->y_scale : 0.f, + 0.f, + font->parent->y_scale ? (float) font->y_scale / (float) font->parent->y_scale : 0.f, + 0.f, 0.f); + + font->parent->paint_glyph (glyph, paint_funcs, paint_data, palette, foreground); + + paint_funcs->pop_transform (paint_data); +} + DEFINE_NULL_INSTANCE (hb_font_funcs_t) = { HB_OBJECT_HEADER_STATIC, @@ -640,7 +687,7 @@ DEFINE_NULL_INSTANCE (hb_font_funcs_t) = nullptr, { { -#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_nil, +#define HB_FONT_FUNC_IMPLEMENT(get_,name) hb_font_##get_##name##_nil, HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT } @@ -654,7 +701,7 @@ static const hb_font_funcs_t _hb_font_funcs_default = { nullptr, { { -#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_default, +#define HB_FONT_FUNC_IMPLEMENT(get_,name) hb_font_##get_##name##_default, HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT } @@ -732,7 +779,7 @@ hb_font_funcs_destroy (hb_font_funcs_t *ffuncs) if (ffuncs->destroy) { -#define HB_FONT_FUNC_IMPLEMENT(name) if (ffuncs->destroy->name) \ +#define HB_FONT_FUNC_IMPLEMENT(get_,name) if (ffuncs->destroy->name) \ ffuncs->destroy->name (!ffuncs->user_data ? nullptr : ffuncs->user_data->name); HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT @@ -822,59 +869,82 @@ hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs) } -#define HB_FONT_FUNC_IMPLEMENT(name) \ +static bool +_hb_font_funcs_set_preamble (hb_font_funcs_t *ffuncs, + bool func_is_null, + void **user_data, + hb_destroy_func_t *destroy) +{ + if (hb_object_is_immutable (ffuncs)) + { + if (*destroy) + (*destroy) (*user_data); + return false; + } + + if (func_is_null) + { + if (*destroy) + (*destroy) (*user_data); + *destroy = nullptr; + *user_data = nullptr; + } + + return true; +} + +static bool +_hb_font_funcs_set_middle (hb_font_funcs_t *ffuncs, + void *user_data, + hb_destroy_func_t destroy) +{ + if (user_data && !ffuncs->user_data) + { + ffuncs->user_data = (decltype (ffuncs->user_data)) hb_calloc (1, sizeof (*ffuncs->user_data)); + if (unlikely (!ffuncs->user_data)) + goto fail; + } + if (destroy && !ffuncs->destroy) + { + ffuncs->destroy = (decltype (ffuncs->destroy)) hb_calloc (1, sizeof (*ffuncs->destroy)); + if (unlikely (!ffuncs->destroy)) + goto fail; + } + + return true; + +fail: + if (destroy) + (destroy) (user_data); + return false; +} + +#define HB_FONT_FUNC_IMPLEMENT(get_,name) \ \ void \ hb_font_funcs_set_##name##_func (hb_font_funcs_t *ffuncs, \ - hb_font_get_##name##_func_t func, \ + hb_font_##get_##name##_func_t func, \ void *user_data, \ hb_destroy_func_t destroy) \ { \ - if (hb_object_is_immutable (ffuncs)) \ - goto fail; \ - \ - if (!func) \ - { \ - if (destroy) \ - destroy (user_data); \ - destroy = nullptr; \ - user_data = nullptr; \ - } \ + if (!_hb_font_funcs_set_preamble (ffuncs, !func, &user_data, &destroy))\ + return; \ \ if (ffuncs->destroy && ffuncs->destroy->name) \ ffuncs->destroy->name (!ffuncs->user_data ? nullptr : ffuncs->user_data->name); \ \ - if (user_data && !ffuncs->user_data) \ - { \ - ffuncs->user_data = (decltype (ffuncs->user_data)) hb_calloc (1, sizeof (*ffuncs->user_data)); \ - if (unlikely (!ffuncs->user_data)) \ - goto fail; \ - } \ - if (destroy && !ffuncs->destroy) \ - { \ - ffuncs->destroy = (decltype (ffuncs->destroy)) hb_calloc (1, sizeof (*ffuncs->destroy)); \ - if (unlikely (!ffuncs->destroy)) \ - goto fail; \ - } \ + if (!_hb_font_funcs_set_middle (ffuncs, user_data, destroy)) \ + return; \ \ - if (func) { \ + if (func) \ ffuncs->get.f.name = func; \ - if (ffuncs->user_data) \ - ffuncs->user_data->name = user_data; \ - if (ffuncs->destroy) \ - ffuncs->destroy->name = destroy; \ - } else { \ - ffuncs->get.f.name = hb_font_get_##name##_default; \ - if (ffuncs->user_data) \ - ffuncs->user_data->name = nullptr; \ - if (ffuncs->destroy) \ - ffuncs->destroy->name = nullptr; \ - } \ - return; \ - \ -fail: \ - if (destroy) \ - destroy (user_data); \ + else \ + ffuncs->get.f.name = hb_font_##get_##name##_default; \ + \ + if (ffuncs->user_data) \ + ffuncs->user_data->name = user_data; \ + if (ffuncs->destroy) \ + ffuncs->destroy->name = destroy; \ } HB_FONT_FUNCS_IMPLEMENT_CALLBACKS @@ -996,7 +1066,8 @@ hb_font_get_nominal_glyph (hb_font_t *font, * @glyph_stride: The stride between successive glyph IDs * * Fetches the nominal glyph IDs for a sequence of Unicode code points. Glyph - * IDs must be returned in a #hb_codepoint_t output parameter. + * IDs must be returned in a #hb_codepoint_t output parameter. Stops at the + * first unsupported glyph ID. * * Return value: the number of code points processed * @@ -1278,6 +1349,9 @@ hb_font_get_glyph_contour_point (hb_font_t *font, * * Fetches the glyph-name string for a glyph ID in the specified @font. * + * According to the OpenType specification, glyph names are limited to 63 + * characters and can only contain (a subset of) ASCII. + * * Return value: `true` if data found, `false` otherwise * * Since: 0.9.2 @@ -1315,25 +1389,81 @@ hb_font_get_glyph_from_name (hb_font_t *font, return font->get_glyph_from_name (name, len, glyph); } +#ifndef HB_DISABLE_DEPRECATED /** * hb_font_get_glyph_shape: * @font: #hb_font_t to work upon - * @glyph: : The glyph ID + * @glyph: The glyph ID * @dfuncs: #hb_draw_funcs_t to draw to * @draw_data: User data to pass to draw callbacks * * Fetches the glyph shape that corresponds to a glyph in the specified @font. - * The shape is returned by way of calls to the callsbacks of the @dfuncs + * The shape is returned by way of calls to the callbacks of the @dfuncs * objects, with @draw_data passed to them. * * Since: 4.0.0 - **/ + * Deprecated: 7.0.0: Use hb_font_draw_glyph() instead + */ void hb_font_get_glyph_shape (hb_font_t *font, + hb_codepoint_t glyph, + hb_draw_funcs_t *dfuncs, void *draw_data) +{ + hb_font_draw_glyph (font, glyph, dfuncs, draw_data); +} +#endif + +/** + * hb_font_draw_glyph: + * @font: #hb_font_t to work upon + * @glyph: The glyph ID + * @dfuncs: #hb_draw_funcs_t to draw to + * @draw_data: User data to pass to draw callbacks + * + * Draws the outline that corresponds to a glyph in the specified @font. + * + * The outline is returned by way of calls to the callbacks of the @dfuncs + * objects, with @draw_data passed to them. + * + * Since: 7.0.0 + **/ +void +hb_font_draw_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_draw_funcs_t *dfuncs, void *draw_data) { - font->get_glyph_shape (glyph, dfuncs, draw_data); + font->draw_glyph (glyph, dfuncs, draw_data); +} + +/** + * hb_font_paint_glyph: + * @font: #hb_font_t to work upon + * @glyph: The glyph ID + * @pfuncs: #hb_paint_funcs_t to paint with + * @paint_data: User data to pass to paint callbacks + * @palette_index: The index of the font's color palette to use + * @foreground: The foreground color, unpremultipled + * + * Paints the glyph. + * + * The painting instructions are returned by way of calls to + * the callbacks of the @funcs object, with @paint_data passed + * to them. + * + * If the font has color palettes (see hb_ot_color_has_palettes()), + * then @palette_index selects the palette to use. If the font only + * has one palette, this will be 0. + * + * Since: 7.0.0 + */ +void +hb_font_paint_glyph (hb_font_t *font, + hb_codepoint_t glyph, + hb_paint_funcs_t *pfuncs, void *paint_data, + unsigned int palette_index, + hb_color_t foreground) +{ + font->paint_glyph (glyph, pfuncs, paint_data, palette_index, foreground); } /* A bit higher-level, and with fallback */ @@ -1594,6 +1724,9 @@ hb_font_get_glyph_contour_point_for_origin (hb_font_t *font, * If the glyph ID has no name in @font, a string of the form `gidDDD` is * generated, with `DDD` being the glyph ID. * + * According to the OpenType specification, glyph names are limited to 63 + * characters and can only contain (a subset of) ASCII. + * * Since: 0.9.2 **/ void @@ -1647,8 +1780,13 @@ DEFINE_NULL_INSTANCE (hb_font_t) = 1000, /* x_scale */ 1000, /* y_scale */ - 0., /* slant */ - 0., /* slant_xy; */ + 0.f, /* x_embolden */ + 0.f, /* y_embolden */ + true, /* embolden_in_place */ + 0, /* x_strength */ + 0, /* y_strength */ + 0.f, /* slant */ + 0.f, /* slant_xy; */ 1.f, /* x_multf */ 1.f, /* y_multf */ 1<<16, /* x_mult */ @@ -1658,6 +1796,7 @@ DEFINE_NULL_INSTANCE (hb_font_t) = 0, /* y_ppem */ 0, /* ptem */ + HB_FONT_NO_VAR_NAMED_INSTANCE, /* instance_index */ 0, /* num_coords */ nullptr, /* coords */ nullptr, /* design_coords */ @@ -1685,8 +1824,10 @@ _hb_font_create (hb_face_t *face) font->klass = hb_font_funcs_get_empty (); font->data.init0 (font); font->x_scale = font->y_scale = face->get_upem (); + font->embolden_in_place = true; font->x_multf = font->y_multf = 1.f; font->x_mult = font->y_mult = 1 << 16; + font->instance_index = HB_FONT_NO_VAR_NAMED_INSTANCE; return font; } @@ -1768,6 +1909,9 @@ hb_font_create_sub_font (hb_font_t *parent) font->x_scale = parent->x_scale; font->y_scale = parent->y_scale; + font->x_embolden = parent->x_embolden; + font->y_embolden = parent->y_embolden; + font->embolden_in_place = parent->embolden_in_place; font->slant = parent->slant; font->x_ppem = parent->x_ppem; font->y_ppem = parent->y_ppem; @@ -1780,8 +1924,8 @@ hb_font_create_sub_font (hb_font_t *parent) float *design_coords = (float *) hb_calloc (num_coords, sizeof (parent->design_coords[0])); if (likely (coords && design_coords)) { - memcpy (coords, parent->coords, num_coords * sizeof (parent->coords[0])); - memcpy (design_coords, parent->design_coords, num_coords * sizeof (parent->design_coords[0])); + hb_memcpy (coords, parent->coords, num_coords * sizeof (parent->coords[0])); + hb_memcpy (design_coords, parent->design_coords, num_coords * sizeof (parent->design_coords[0])); _hb_font_adopt_var_coords (font, coords, design_coords, num_coords); } else @@ -2157,6 +2301,31 @@ hb_font_set_funcs_data (hb_font_t *font, * * Sets the horizontal and vertical scale of a font. * + * The font scale is a number related to, but not the same as, + * font size. Typically the client establishes a scale factor + * to be used between the two. For example, 64, or 256, which + * would be the fractional-precision part of the font scale. + * This is necessary because #hb_position_t values are integer + * types and you need to leave room for fractional values + * in there. + * + * For example, to set the font size to 20, with 64 + * levels of fractional precision you would call + * `hb_font_set_scale(font, 20 * 64, 20 * 64)`. + * + * In the example above, even what font size 20 means is up to + * you. It might be 20 pixels, or 20 points, or 20 millimeters. + * HarfBuzz does not care about that. You can set the point + * size of the font using hb_font_set_ptem(), and the pixel + * size using hb_font_set_ppem(). + * + * The choice of scale is yours but needs to be consistent between + * what you set here, and what you expect out of #hb_position_t + * as well has draw / paint API output values. + * + * Fonts default to a scale equal to the UPEM value of their face. + * A font with this setting is sometimes called an "unscaled" font. + * * Since: 0.9.2 **/ void @@ -2202,7 +2371,11 @@ hb_font_get_scale (hb_font_t *font, * @x_ppem: Horizontal ppem value to assign * @y_ppem: Vertical ppem value to assign * - * Sets the horizontal and vertical pixels-per-em (ppem) of a font. + * Sets the horizontal and vertical pixels-per-em (PPEM) of a font. + * + * These values are used for pixel-size-specific adjustment to + * shaping and draw results, though for the most part they are + * unused and can be left unset. * * Since: 0.9.2 **/ @@ -2286,6 +2459,76 @@ hb_font_get_ptem (hb_font_t *font) return font->ptem; } +/** + * hb_font_set_synthetic_bold: + * @font: #hb_font_t to work upon + * @x_embolden: the amount to embolden horizontally + * @y_embolden: the amount to embolden vertically + * @in_place: whether to embolden glyphs in-place + * + * Sets the "synthetic boldness" of a font. + * + * Positive values for @x_embolden / @y_embolden make a font + * bolder, negative values thinner. Typical values are in the + * 0.01 to 0.05 range. The default value is zero. + * + * Synthetic boldness is applied by offsetting the contour + * points of the glyph shape. + * + * Synthetic boldness is applied when rendering a glyph via + * hb_font_draw_glyph(). + * + * If @in_place is `false`, then glyph advance-widths are also + * adjusted, otherwise they are not. The in-place mode is + * useful for simulating [font grading](https://fonts.google.com/knowledge/glossary/grade). + * + * + * Since: 7.0.0 + **/ +void +hb_font_set_synthetic_bold (hb_font_t *font, + float x_embolden, + float y_embolden, + hb_bool_t in_place) +{ + if (hb_object_is_immutable (font)) + return; + + if (font->x_embolden == x_embolden && + font->y_embolden == y_embolden && + font->embolden_in_place == (bool) in_place) + return; + + font->serial++; + + font->x_embolden = x_embolden; + font->y_embolden = y_embolden; + font->embolden_in_place = in_place; + font->mults_changed (); +} + +/** + * hb_font_get_synthetic_bold: + * @font: #hb_font_t to work upon + * @x_embolden: (out): return location for horizontal value + * @y_embolden: (out): return location for vertical value + * @in_place: (out): return location for in-place value + * + * Fetches the "synthetic boldness" parameters of a font. + * + * Since: 7.0.0 + **/ +void +hb_font_get_synthetic_bold (hb_font_t *font, + float *x_embolden, + float *y_embolden, + hb_bool_t *in_place) +{ + if (x_embolden) *x_embolden = font->x_embolden; + if (y_embolden) *y_embolden = font->y_embolden; + if (in_place) *in_place = font->embolden_in_place; +} + /** * hb_font_set_synthetic_slant: * @font: #hb_font_t to work upon @@ -2298,9 +2541,8 @@ hb_font_get_ptem (hb_font_t *font) * HarfBuzz needs to know this value to adjust shaping results, * metrics, and style values to match the slanted rendering. * - * Note: The glyph shape fetched via the - * hb_font_get_glyph_shape() is slanted to reflect this value - * as well. + * Note: The glyph shape fetched via the hb_font_draw_glyph() + * function is slanted to reflect this value as well. * * Note: The slant value is a ratio. For example, a * 20% slant would be represented as a 0.2 value. @@ -2367,7 +2609,7 @@ hb_font_set_variations (hb_font_t *font, font->serial_coords = ++font->serial; - if (!variations_length) + if (!variations_length && font->instance_index == HB_FONT_NO_VAR_NAMED_INSTANCE) { hb_font_set_var_coords_normalized (font, nullptr, 0); return; @@ -2387,9 +2629,18 @@ hb_font_set_variations (hb_font_t *font, return; } - /* Initialize design coords to default from fvar. */ + /* Initialize design coords. */ for (unsigned int i = 0; i < coords_length; i++) design_coords[i] = axes[i].get_default (); + if (font->instance_index != HB_FONT_NO_VAR_NAMED_INSTANCE) + { + unsigned count = coords_length; + /* This may fail if index is out-of-range; + * That's why we initialize design_coords from fvar above + * unconditionally. */ + hb_ot_var_named_instance_get_design_coords (font->face, font->instance_index, + &count, design_coords); + } for (unsigned int i = 0; i < variations_length; i++) { @@ -2397,14 +2648,82 @@ hb_font_set_variations (hb_font_t *font, const auto v = variations[i].value; for (unsigned axis_index = 0; axis_index < coords_length; axis_index++) if (axes[axis_index].axisTag == tag) - { design_coords[axis_index] = v; - normalized[axis_index] = fvar.normalize_axis_value (axis_index, v); - } } - font->face->table.avar->map_coords (normalized, coords_length); + hb_ot_var_normalize_coords (font->face, coords_length, design_coords, normalized); + _hb_font_adopt_var_coords (font, normalized, design_coords, coords_length); +} + +/** + * hb_font_set_variation: + * @font: #hb_font_t to work upon + * @tag: The #hb_tag_t tag of the variation-axis name + * @value: The value of the variation axis + * + * Change the value of one variation axis on the font. + * + * Note: This function is expensive to be called repeatedly. + * If you want to set multiple variation axes at the same time, + * use hb_font_set_variations() instead. + * + * Since: 7.1.0 + */ +void +hb_font_set_variation (hb_font_t *font, + hb_tag_t tag, + float value) +{ + if (hb_object_is_immutable (font)) + return; + + font->serial_coords = ++font->serial; + + // TODO Share some of this code with set_variations() + + const OT::fvar &fvar = *font->face->table.fvar; + auto axes = fvar.get_axes (); + const unsigned coords_length = axes.length; + + int *normalized = coords_length ? (int *) hb_calloc (coords_length, sizeof (int)) : nullptr; + float *design_coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (float)) : nullptr; + + if (unlikely (coords_length && !(normalized && design_coords))) + { + hb_free (normalized); + hb_free (design_coords); + return; + } + + /* Initialize design coords. */ + if (font->design_coords) + { + assert (coords_length == font->num_coords); + for (unsigned int i = 0; i < coords_length; i++) + design_coords[i] = font->design_coords[i]; + } + else + { + for (unsigned int i = 0; i < coords_length; i++) + design_coords[i] = axes[i].get_default (); + if (font->instance_index != HB_FONT_NO_VAR_NAMED_INSTANCE) + { + unsigned count = coords_length; + /* This may fail if index is out-of-range; + * That's why we initialize design_coords from fvar above + * unconditionally. */ + hb_ot_var_named_instance_get_design_coords (font->face, font->instance_index, + &count, design_coords); + } + } + + for (unsigned axis_index = 0; axis_index < coords_length; axis_index++) + if (axes[axis_index].axisTag == tag) + design_coords[axis_index] = value; + + hb_ot_var_normalize_coords (font->face, coords_length, design_coords, normalized); _hb_font_adopt_var_coords (font, normalized, design_coords, coords_length); + } /** @@ -2443,7 +2762,7 @@ hb_font_set_var_coords_design (hb_font_t *font, } if (coords_length) - memcpy (design_coords, coords, coords_length * sizeof (font->design_coords[0])); + hb_memcpy (design_coords, coords, coords_length * sizeof (font->design_coords[0])); hb_ot_var_normalize_coords (font->face, coords_length, coords, normalized); _hb_font_adopt_var_coords (font, normalized, design_coords, coords_length); @@ -2454,28 +2773,40 @@ hb_font_set_var_coords_design (hb_font_t *font, * @font: a font. * @instance_index: named instance index. * - * Sets design coords of a font from a named instance index. + * Sets design coords of a font from a named-instance index. * * Since: 2.6.0 */ void hb_font_set_var_named_instance (hb_font_t *font, - unsigned instance_index) + unsigned int instance_index) { if (hb_object_is_immutable (font)) return; - font->serial_coords = ++font->serial; + if (font->instance_index == instance_index) + return; - unsigned int coords_length = hb_ot_var_named_instance_get_design_coords (font->face, instance_index, nullptr, nullptr); + font->serial_coords = ++font->serial; - float *coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (float)) : nullptr; - if (unlikely (coords_length && !coords)) - return; + font->instance_index = instance_index; + hb_font_set_variations (font, nullptr, 0); +} - hb_ot_var_named_instance_get_design_coords (font->face, instance_index, &coords_length, coords); - hb_font_set_var_coords_design (font, coords, coords_length); - hb_free (coords); +/** + * hb_font_get_var_named_instance: + * @font: a font. + * + * Returns the currently-set named-instance index of the font. + * + * Return value: Named-instance index or %HB_FONT_NO_VAR_NAMED_INSTANCE. + * + * Since: 7.0.0 + **/ +unsigned int +hb_font_get_var_named_instance (hb_font_t *font) +{ + return font->instance_index; } /** @@ -2519,8 +2850,8 @@ hb_font_set_var_coords_normalized (hb_font_t *font, if (coords_length) { - memcpy (copy, coords, coords_length * sizeof (coords[0])); - memcpy (unmapped, coords, coords_length * sizeof (coords[0])); + hb_memcpy (copy, coords, coords_length * sizeof (coords[0])); + hb_memcpy (unmapped, coords, coords_length * sizeof (coords[0])); } /* Best effort design coords simulation */ @@ -2724,3 +3055,15 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs, trampoline_destroy); } #endif + + +#ifndef HB_DISABLE_DEPRECATED +void +hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_shape_func_t func, + void *user_data, + hb_destroy_func_t destroy /* May be NULL. */) +{ + hb_font_funcs_set_draw_glyph_func (ffuncs, func, user_data, destroy); +} +#endif diff --git a/libs/harfbuzz/src/hb-font.h b/libs/harfbuzz/src/hb-font.h index e2c3df4a5..3c2355af2 100644 --- a/libs/harfbuzz/src/hb-font.h +++ b/libs/harfbuzz/src/hb-font.h @@ -34,18 +34,10 @@ #include "hb-common.h" #include "hb-face.h" #include "hb-draw.h" +#include "hb-paint.h" HB_BEGIN_DECLS -/** - * hb_font_t: - * - * Data type for holding fonts. - * - */ -typedef struct hb_font_t hb_font_t; - - /* * hb_font_funcs_t */ @@ -97,7 +89,7 @@ HB_EXTERN hb_bool_t hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs); -/* font and glyph extents */ +/* font extents */ /** * hb_font_extents_t: @@ -126,24 +118,6 @@ typedef struct hb_font_extents_t { hb_position_t reserved1; } hb_font_extents_t; -/** - * hb_glyph_extents_t: - * @x_bearing: Distance from the x-origin to the left extremum of the glyph. - * @y_bearing: Distance from the top extremum of the glyph to the y-origin. - * @width: Distance from the left extremum of the glyph to the right extremum. - * @height: Distance from the top extremum of the glyph to the bottom extremum. - * - * Glyph extent values, measured in font units. - * - * Note that @height is negative, in coordinate systems that grow up. - **/ -typedef struct hb_glyph_extents_t { - hb_position_t x_bearing; - hb_position_t y_bearing; - hb_position_t width; - hb_position_t height; -} hb_glyph_extents_t; - /* func types */ /** @@ -512,7 +486,7 @@ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void * void *user_data); /** - * hb_font_get_glyph_shape_func_t: + * hb_font_draw_glyph_func_t: * @font: #hb_font_t to work upon * @font_data: @font user data pointer * @glyph: The glyph ID to query @@ -522,14 +496,35 @@ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void * * * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. * - * Since: 4.0.0 + * Since: 7.0.0 * **/ -typedef void (*hb_font_get_glyph_shape_func_t) (hb_font_t *font, void *font_data, - hb_codepoint_t glyph, - hb_draw_funcs_t *draw_funcs, void *draw_data, - void *user_data); +typedef void (*hb_font_draw_glyph_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, void *draw_data, + void *user_data); +/** + * hb_font_paint_glyph_func_t: + * @font: #hb_font_t to work upon + * @font_data: @font user data pointer + * @glyph: The glyph ID to query + * @paint_funcs: The paint functions to use + * @paint_data: The data accompanying the paint functions + * @palette_index: The color palette to use + * @foreground: The foreground color + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * Since: 7.0.0 + */ +typedef void (*hb_font_paint_glyph_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t glyph, + hb_paint_funcs_t *paint_funcs, void *paint_data, + unsigned int palette_index, + hb_color_t foreground, + void *user_data); /* func setters */ @@ -790,20 +785,36 @@ hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs, void *user_data, hb_destroy_func_t destroy); /** - * hb_font_funcs_set_glyph_shape_func: + * hb_font_funcs_set_draw_glyph_func: * @ffuncs: A font-function structure * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign * @user_data: Data to pass to @func * @destroy: (nullable): The function to call when @user_data is not needed anymore * - * Sets the implementation function for #hb_font_get_glyph_shape_func_t. + * Sets the implementation function for #hb_font_draw_glyph_func_t. * - * Since: 4.0.0 + * Since: 7.0.0 **/ HB_EXTERN void -hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs, - hb_font_get_glyph_shape_func_t func, - void *user_data, hb_destroy_func_t destroy); +hb_font_funcs_set_draw_glyph_func (hb_font_funcs_t *ffuncs, + hb_font_draw_glyph_func_t func, + void *user_data, hb_destroy_func_t destroy); + +/** + * hb_font_funcs_set_paint_glyph_func: + * @ffuncs: A font-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is no longer needed + * + * Sets the implementation function for #hb_font_paint_glyph_func_t. + * + * Since: 7.0.0 + */ +HB_EXTERN void +hb_font_funcs_set_paint_glyph_func (hb_font_funcs_t *ffuncs, + hb_font_paint_glyph_func_t func, + void *user_data, hb_destroy_func_t destroy); /* func dispatch */ @@ -886,10 +897,16 @@ hb_font_get_glyph_from_name (hb_font_t *font, hb_codepoint_t *glyph); HB_EXTERN void -hb_font_get_glyph_shape (hb_font_t *font, - hb_codepoint_t glyph, - hb_draw_funcs_t *dfuncs, void *draw_data); +hb_font_draw_glyph (hb_font_t *font, + hb_codepoint_t glyph, + hb_draw_funcs_t *dfuncs, void *draw_data); +HB_EXTERN void +hb_font_paint_glyph (hb_font_t *font, + hb_codepoint_t glyph, + hb_paint_funcs_t *pfuncs, void *paint_data, + unsigned int palette_index, + hb_color_t foreground); /* high-level funcs, with fallback */ @@ -1069,6 +1086,16 @@ hb_font_set_ptem (hb_font_t *font, float ptem); HB_EXTERN float hb_font_get_ptem (hb_font_t *font); +HB_EXTERN void +hb_font_set_synthetic_bold (hb_font_t *font, + float x_embolden, float y_embolden, + hb_bool_t in_place); + +HB_EXTERN void +hb_font_get_synthetic_bold (hb_font_t *font, + float *x_embolden, float *y_embolden, + hb_bool_t *in_place); + HB_EXTERN void hb_font_set_synthetic_slant (hb_font_t *font, float slant); @@ -1080,6 +1107,11 @@ hb_font_set_variations (hb_font_t *font, const hb_variation_t *variations, unsigned int variations_length); +HB_EXTERN void +hb_font_set_variation (hb_font_t *font, + hb_tag_t tag, + float value); + HB_EXTERN void hb_font_set_var_coords_design (hb_font_t *font, const float *coords, @@ -1098,10 +1130,23 @@ HB_EXTERN const int * hb_font_get_var_coords_normalized (hb_font_t *font, unsigned int *length); +/** + * HB_FONT_NO_VAR_NAMED_INSTANCE: + * + * Constant signifying that a font does not have any + * named-instance index set. This is the default of + * a font. + * + * Since: 7.0.0 + */ +#define HB_FONT_NO_VAR_NAMED_INSTANCE 0xFFFFFFFF + HB_EXTERN void hb_font_set_var_named_instance (hb_font_t *font, - unsigned instance_index); + unsigned int instance_index); +HB_EXTERN unsigned int +hb_font_get_var_named_instance (hb_font_t *font); HB_END_DECLS diff --git a/libs/harfbuzz/src/hb-font.hh b/libs/harfbuzz/src/hb-font.hh index bb402e23e..4c8190b0d 100644 --- a/libs/harfbuzz/src/hb-font.hh +++ b/libs/harfbuzz/src/hb-font.hh @@ -40,24 +40,25 @@ */ #define HB_FONT_FUNCS_IMPLEMENT_CALLBACKS \ - HB_FONT_FUNC_IMPLEMENT (font_h_extents) \ - HB_FONT_FUNC_IMPLEMENT (font_v_extents) \ - HB_FONT_FUNC_IMPLEMENT (nominal_glyph) \ - HB_FONT_FUNC_IMPLEMENT (nominal_glyphs) \ - HB_FONT_FUNC_IMPLEMENT (variation_glyph) \ - HB_FONT_FUNC_IMPLEMENT (glyph_h_advance) \ - HB_FONT_FUNC_IMPLEMENT (glyph_v_advance) \ - HB_FONT_FUNC_IMPLEMENT (glyph_h_advances) \ - HB_FONT_FUNC_IMPLEMENT (glyph_v_advances) \ - HB_FONT_FUNC_IMPLEMENT (glyph_h_origin) \ - HB_FONT_FUNC_IMPLEMENT (glyph_v_origin) \ - HB_FONT_FUNC_IMPLEMENT (glyph_h_kerning) \ - HB_IF_NOT_DEPRECATED (HB_FONT_FUNC_IMPLEMENT (glyph_v_kerning)) \ - HB_FONT_FUNC_IMPLEMENT (glyph_extents) \ - HB_FONT_FUNC_IMPLEMENT (glyph_contour_point) \ - HB_FONT_FUNC_IMPLEMENT (glyph_name) \ - HB_FONT_FUNC_IMPLEMENT (glyph_from_name) \ - HB_FONT_FUNC_IMPLEMENT (glyph_shape) \ + HB_FONT_FUNC_IMPLEMENT (get_,font_h_extents) \ + HB_FONT_FUNC_IMPLEMENT (get_,font_v_extents) \ + HB_FONT_FUNC_IMPLEMENT (get_,nominal_glyph) \ + HB_FONT_FUNC_IMPLEMENT (get_,nominal_glyphs) \ + HB_FONT_FUNC_IMPLEMENT (get_,variation_glyph) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_h_advance) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_v_advance) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_h_advances) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_v_advances) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_h_origin) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_v_origin) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_h_kerning) \ + HB_IF_NOT_DEPRECATED (HB_FONT_FUNC_IMPLEMENT (get_,glyph_v_kerning)) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_extents) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_contour_point) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_name) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_from_name) \ + HB_FONT_FUNC_IMPLEMENT (,draw_glyph) \ + HB_FONT_FUNC_IMPLEMENT (,paint_glyph) \ /* ^--- Add new callbacks here */ struct hb_font_funcs_t @@ -65,13 +66,13 @@ struct hb_font_funcs_t hb_object_header_t header; struct { -#define HB_FONT_FUNC_IMPLEMENT(name) void *name; +#define HB_FONT_FUNC_IMPLEMENT(get_,name) void *name; HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT } *user_data; struct { -#define HB_FONT_FUNC_IMPLEMENT(name) hb_destroy_func_t name; +#define HB_FONT_FUNC_IMPLEMENT(get_,name) hb_destroy_func_t name; HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT } *destroy; @@ -79,12 +80,12 @@ struct hb_font_funcs_t /* Don't access these directly. Call font->get_*() instead. */ union get_t { struct get_funcs_t { -#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_func_t name; +#define HB_FONT_FUNC_IMPLEMENT(get_,name) hb_font_##get_##name##_func_t name; HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT } f; void (*array[0 -#define HB_FONT_FUNC_IMPLEMENT(name) +1 +#define HB_FONT_FUNC_IMPLEMENT(get_,name) +1 HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT ]) (); @@ -112,8 +113,16 @@ struct hb_font_t int32_t x_scale; int32_t y_scale; + + float x_embolden; + float y_embolden; + bool embolden_in_place; + int32_t x_strength; /* x_embolden, in scaled units. */ + int32_t y_strength; /* y_embolden, in scaled units. */ + float slant; float slant_xy; + float x_multf; float y_multf; int64_t x_mult; @@ -125,6 +134,7 @@ struct hb_font_t float ptem; /* Font variation coordinates. */ + unsigned int instance_index; unsigned int num_coords; int *coords; float *design_coords; @@ -179,6 +189,42 @@ struct hb_font_t *y = parent_scale_y_position (*y); } + void scale_glyph_extents (hb_glyph_extents_t *extents) + { + float x1 = em_fscale_x (extents->x_bearing); + float y1 = em_fscale_y (extents->y_bearing); + float x2 = em_fscale_x (extents->x_bearing + extents->width); + float y2 = em_fscale_y (extents->y_bearing + extents->height); + + /* Apply slant. */ + if (slant_xy) + { + x1 += hb_min (y1 * slant_xy, y2 * slant_xy); + x2 += hb_max (y1 * slant_xy, y2 * slant_xy); + } + + extents->x_bearing = floorf (x1); + extents->y_bearing = floorf (y1); + extents->width = ceilf (x2) - extents->x_bearing; + extents->height = ceilf (y2) - extents->y_bearing; + + if (x_strength || y_strength) + { + /* Y */ + int y_shift = y_strength; + if (y_scale < 0) y_shift = -y_shift; + extents->y_bearing += y_shift; + extents->height -= y_shift; + + /* X */ + int x_shift = x_strength; + if (x_scale < 0) x_shift = -x_shift; + if (embolden_in_place) + extents->x_bearing -= x_shift / 2; + extents->width += x_shift; + } + } + /* Public getters */ @@ -186,7 +232,7 @@ struct hb_font_t HB_INTERNAL bool has_func_set (unsigned int i); /* has_* ... */ -#define HB_FONT_FUNC_IMPLEMENT(name) \ +#define HB_FONT_FUNC_IMPLEMENT(get_,name) \ bool \ has_##name##_func () \ { \ @@ -206,14 +252,14 @@ struct hb_font_t hb_bool_t get_font_h_extents (hb_font_extents_t *extents) { - memset (extents, 0, sizeof (*extents)); + hb_memset (extents, 0, sizeof (*extents)); return klass->get.f.font_h_extents (this, user_data, extents, !klass->user_data ? nullptr : klass->user_data->font_h_extents); } hb_bool_t get_font_v_extents (hb_font_extents_t *extents) { - memset (extents, 0, sizeof (*extents)); + hb_memset (extents, 0, sizeof (*extents)); return klass->get.f.font_v_extents (this, user_data, extents, !klass->user_data ? nullptr : klass->user_data->font_v_extents); @@ -342,7 +388,7 @@ struct hb_font_t hb_bool_t get_glyph_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) { - memset (extents, 0, sizeof (*extents)); + hb_memset (extents, 0, sizeof (*extents)); return klass->get.f.glyph_extents (this, user_data, glyph, extents, @@ -380,15 +426,26 @@ struct hb_font_t !klass->user_data ? nullptr : klass->user_data->glyph_from_name); } - void get_glyph_shape (hb_codepoint_t glyph, - hb_draw_funcs_t *draw_funcs, void *draw_data) + void draw_glyph (hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, void *draw_data) { - klass->get.f.glyph_shape (this, user_data, - glyph, - draw_funcs, draw_data, - !klass->user_data ? nullptr : klass->user_data->glyph_shape); + klass->get.f.draw_glyph (this, user_data, + glyph, + draw_funcs, draw_data, + !klass->user_data ? nullptr : klass->user_data->draw_glyph); } + void paint_glyph (hb_codepoint_t glyph, + hb_paint_funcs_t *paint_funcs, void *paint_data, + unsigned int palette, + hb_color_t foreground) + { + klass->get.f.paint_glyph (this, user_data, + glyph, + paint_funcs, paint_data, + palette, foreground, + !klass->user_data ? nullptr : klass->user_data->paint_glyph); + } /* A bit higher-level, and with fallback */ @@ -594,7 +651,7 @@ struct hb_font_t { if (get_glyph_name (glyph, s, size)) return; - if (size && snprintf (s, size, "gid%u", glyph) < 0) + if (size && snprintf (s, size, "gid%" PRIu32, glyph) < 0) *s = '\0'; } @@ -632,12 +689,17 @@ struct hb_font_t void mults_changed () { float upem = face->get_upem (); + x_multf = x_scale / upem; y_multf = y_scale / upem; bool x_neg = x_scale < 0; x_mult = (x_neg ? -((int64_t) -x_scale << 16) : ((int64_t) x_scale << 16)) / upem; bool y_neg = y_scale < 0; y_mult = (y_neg ? -((int64_t) -y_scale << 16) : ((int64_t) y_scale << 16)) / upem; + + x_strength = fabsf (roundf (x_scale * x_embolden)); + y_strength = fabsf (roundf (y_scale * y_embolden)); + slant_xy = y_scale ? slant * x_scale / y_scale : 0.f; data.fini (); diff --git a/libs/harfbuzz/src/hb-ft-colr.hh b/libs/harfbuzz/src/hb-ft-colr.hh new file mode 100644 index 000000000..8766a2a2c --- /dev/null +++ b/libs/harfbuzz/src/hb-ft-colr.hh @@ -0,0 +1,601 @@ +/* + * Copyright © 2022 Behdad Esfahbod + * + * 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. + */ + +#ifndef HB_FT_COLR_HH +#define HB_FT_COLR_HH + +#include "hb.hh" + +#include "hb-paint-extents.hh" + +#include FT_COLOR_H + + +static hb_paint_composite_mode_t +_hb_ft_paint_composite_mode (FT_Composite_Mode mode) +{ + switch (mode) + { + case FT_COLR_COMPOSITE_CLEAR: return HB_PAINT_COMPOSITE_MODE_CLEAR; + case FT_COLR_COMPOSITE_SRC: return HB_PAINT_COMPOSITE_MODE_SRC; + case FT_COLR_COMPOSITE_DEST: return HB_PAINT_COMPOSITE_MODE_DEST; + case FT_COLR_COMPOSITE_SRC_OVER: return HB_PAINT_COMPOSITE_MODE_SRC_OVER; + case FT_COLR_COMPOSITE_DEST_OVER: return HB_PAINT_COMPOSITE_MODE_DEST_OVER; + case FT_COLR_COMPOSITE_SRC_IN: return HB_PAINT_COMPOSITE_MODE_SRC_IN; + case FT_COLR_COMPOSITE_DEST_IN: return HB_PAINT_COMPOSITE_MODE_DEST_IN; + case FT_COLR_COMPOSITE_SRC_OUT: return HB_PAINT_COMPOSITE_MODE_SRC_OUT; + case FT_COLR_COMPOSITE_DEST_OUT: return HB_PAINT_COMPOSITE_MODE_DEST_OUT; + case FT_COLR_COMPOSITE_SRC_ATOP: return HB_PAINT_COMPOSITE_MODE_SRC_ATOP; + case FT_COLR_COMPOSITE_DEST_ATOP: return HB_PAINT_COMPOSITE_MODE_DEST_ATOP; + case FT_COLR_COMPOSITE_XOR: return HB_PAINT_COMPOSITE_MODE_XOR; + case FT_COLR_COMPOSITE_PLUS: return HB_PAINT_COMPOSITE_MODE_PLUS; + case FT_COLR_COMPOSITE_SCREEN: return HB_PAINT_COMPOSITE_MODE_SCREEN; + case FT_COLR_COMPOSITE_OVERLAY: return HB_PAINT_COMPOSITE_MODE_OVERLAY; + case FT_COLR_COMPOSITE_DARKEN: return HB_PAINT_COMPOSITE_MODE_DARKEN; + case FT_COLR_COMPOSITE_LIGHTEN: return HB_PAINT_COMPOSITE_MODE_LIGHTEN; + case FT_COLR_COMPOSITE_COLOR_DODGE: return HB_PAINT_COMPOSITE_MODE_COLOR_DODGE; + case FT_COLR_COMPOSITE_COLOR_BURN: return HB_PAINT_COMPOSITE_MODE_COLOR_BURN; + case FT_COLR_COMPOSITE_HARD_LIGHT: return HB_PAINT_COMPOSITE_MODE_HARD_LIGHT; + case FT_COLR_COMPOSITE_SOFT_LIGHT: return HB_PAINT_COMPOSITE_MODE_SOFT_LIGHT; + case FT_COLR_COMPOSITE_DIFFERENCE: return HB_PAINT_COMPOSITE_MODE_DIFFERENCE; + case FT_COLR_COMPOSITE_EXCLUSION: return HB_PAINT_COMPOSITE_MODE_EXCLUSION; + case FT_COLR_COMPOSITE_MULTIPLY: return HB_PAINT_COMPOSITE_MODE_MULTIPLY; + case FT_COLR_COMPOSITE_HSL_HUE: return HB_PAINT_COMPOSITE_MODE_HSL_HUE; + case FT_COLR_COMPOSITE_HSL_SATURATION: return HB_PAINT_COMPOSITE_MODE_HSL_SATURATION; + case FT_COLR_COMPOSITE_HSL_COLOR: return HB_PAINT_COMPOSITE_MODE_HSL_COLOR; + case FT_COLR_COMPOSITE_HSL_LUMINOSITY: return HB_PAINT_COMPOSITE_MODE_HSL_LUMINOSITY; + + case FT_COLR_COMPOSITE_MAX: HB_FALLTHROUGH; + default: return HB_PAINT_COMPOSITE_MODE_CLEAR; + } +} + +typedef struct hb_ft_paint_context_t hb_ft_paint_context_t; + +static void +_hb_ft_paint (hb_ft_paint_context_t *c, + FT_OpaquePaint opaque_paint); + +struct hb_ft_paint_context_t +{ + hb_ft_paint_context_t (const hb_ft_font_t *ft_font, + hb_font_t *font, + hb_paint_funcs_t *paint_funcs, void *paint_data, + FT_Color *palette, + unsigned palette_index, + hb_color_t foreground) : + ft_font (ft_font), font(font), + funcs (paint_funcs), data (paint_data), + palette (palette), palette_index (palette_index), foreground (foreground) {} + + void recurse (FT_OpaquePaint paint) + { + if (unlikely (depth_left <= 0 || edge_count <= 0)) return; + depth_left--; + edge_count--; + _hb_ft_paint (this, paint); + depth_left++; + } + + const hb_ft_font_t *ft_font; + hb_font_t *font; + hb_paint_funcs_t *funcs; + void *data; + FT_Color *palette; + unsigned palette_index; + hb_color_t foreground; + hb_map_t current_glyphs; + hb_map_t current_layers; + int depth_left = HB_MAX_NESTING_LEVEL; + int edge_count = HB_MAX_GRAPH_EDGE_COUNT; +}; + +static unsigned +_hb_ft_color_line_get_color_stops (hb_color_line_t *color_line, + void *color_line_data, + unsigned int start, + unsigned int *count, + hb_color_stop_t *color_stops, + void *user_data) +{ + FT_ColorLine *cl = (FT_ColorLine *) color_line_data; + hb_ft_paint_context_t *c = (hb_ft_paint_context_t *) user_data; + + if (count) + { + FT_ColorStop stop; + unsigned wrote = 0; + FT_ColorStopIterator iter = cl->color_stop_iterator; + + if (start >= cl->color_stop_iterator.num_color_stops) + { + *count = 0; + return cl->color_stop_iterator.num_color_stops; + } + + while (cl->color_stop_iterator.current_color_stop < start) + FT_Get_Colorline_Stops(c->ft_font->ft_face, + &stop, + &cl->color_stop_iterator); + + while (count && *count && + FT_Get_Colorline_Stops(c->ft_font->ft_face, + &stop, + &cl->color_stop_iterator)) + { + // https://github.com/harfbuzz/harfbuzz/issues/4013 + if (sizeof stop.stop_offset == 2) + color_stops->offset = stop.stop_offset / 16384.f; + else + color_stops->offset = stop.stop_offset / 65536.f; + + color_stops->is_foreground = stop.color.palette_index == 0xFFFF; + if (color_stops->is_foreground) + color_stops->color = HB_COLOR (hb_color_get_blue (c->foreground), + hb_color_get_green (c->foreground), + hb_color_get_red (c->foreground), + (hb_color_get_alpha (c->foreground) * stop.color.alpha) >> 14); + else + { + hb_color_t color; + if (c->funcs->custom_palette_color (c->data, stop.color.palette_index, &color)) + { + color_stops->color = HB_COLOR (hb_color_get_blue (color), + hb_color_get_green (color), + hb_color_get_red (color), + (hb_color_get_alpha (color) * stop.color.alpha) >> 14); + } + else + { + FT_Color ft_color = c->palette[stop.color.palette_index]; + color_stops->color = HB_COLOR (ft_color.blue, + ft_color.green, + ft_color.red, + (ft_color.alpha * stop.color.alpha) >> 14); + } + } + + color_stops++; + wrote++; + } + + *count = wrote; + + // reset the iterator for next time + cl->color_stop_iterator = iter; + } + + return cl->color_stop_iterator.num_color_stops; +} + +static hb_paint_extend_t +_hb_ft_color_line_get_extend (hb_color_line_t *color_line, + void *color_line_data, + void *user_data) +{ + FT_ColorLine *c = (FT_ColorLine *) color_line_data; + switch (c->extend) + { + default: + case FT_COLR_PAINT_EXTEND_PAD: return HB_PAINT_EXTEND_PAD; + case FT_COLR_PAINT_EXTEND_REPEAT: return HB_PAINT_EXTEND_REPEAT; + case FT_COLR_PAINT_EXTEND_REFLECT: return HB_PAINT_EXTEND_REFLECT; + } +} + +void +_hb_ft_paint (hb_ft_paint_context_t *c, + FT_OpaquePaint opaque_paint) +{ + FT_Face ft_face = c->ft_font->ft_face; + FT_COLR_Paint paint; + if (!FT_Get_Paint (ft_face, opaque_paint, &paint)) + return; + + switch (paint.format) + { + case FT_COLR_PAINTFORMAT_COLR_LAYERS: + { + FT_OpaquePaint other_paint = {0}; + while (FT_Get_Paint_Layers (ft_face, + &paint.u.colr_layers.layer_iterator, + &other_paint)) + { + unsigned i = paint.u.colr_layers.layer_iterator.layer; + + if (unlikely (c->current_layers.has (i))) + continue; + + c->current_layers.add (i); + + c->funcs->push_group (c->data); + c->recurse (other_paint); + c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER); + + c->current_layers.del (i); + } + } + break; + case FT_COLR_PAINTFORMAT_SOLID: + { + bool is_foreground = paint.u.solid.color.palette_index == 0xFFFF; + hb_color_t color; + if (is_foreground) + color = HB_COLOR (hb_color_get_blue (c->foreground), + hb_color_get_green (c->foreground), + hb_color_get_red (c->foreground), + (hb_color_get_alpha (c->foreground) * paint.u.solid.color.alpha) >> 14); + else + { + if (c->funcs->custom_palette_color (c->data, paint.u.solid.color.palette_index, &color)) + { + color = HB_COLOR (hb_color_get_blue (color), + hb_color_get_green (color), + hb_color_get_red (color), + (hb_color_get_alpha (color) * paint.u.solid.color.alpha) >> 14); + } + else + { + FT_Color ft_color = c->palette[paint.u.solid.color.palette_index]; + color = HB_COLOR (ft_color.blue, + ft_color.green, + ft_color.red, + (ft_color.alpha * paint.u.solid.color.alpha) >> 14); + } + } + c->funcs->color (c->data, is_foreground, color); + } + break; + case FT_COLR_PAINTFORMAT_LINEAR_GRADIENT: + { + hb_color_line_t cl = { + &paint.u.linear_gradient.colorline, + _hb_ft_color_line_get_color_stops, c, + _hb_ft_color_line_get_extend, nullptr + }; + + c->funcs->linear_gradient (c->data, &cl, + paint.u.linear_gradient.p0.x / 65536.f, + paint.u.linear_gradient.p0.y / 65536.f, + paint.u.linear_gradient.p1.x / 65536.f, + paint.u.linear_gradient.p1.y / 65536.f, + paint.u.linear_gradient.p2.x / 65536.f, + paint.u.linear_gradient.p2.y / 65536.f); + } + break; + case FT_COLR_PAINTFORMAT_RADIAL_GRADIENT: + { + hb_color_line_t cl = { + &paint.u.linear_gradient.colorline, + _hb_ft_color_line_get_color_stops, c, + _hb_ft_color_line_get_extend, nullptr + }; + + c->funcs->radial_gradient (c->data, &cl, + paint.u.radial_gradient.c0.x / 65536.f, + paint.u.radial_gradient.c0.y / 65536.f, + paint.u.radial_gradient.r0 / 65536.f, + paint.u.radial_gradient.c1.x / 65536.f, + paint.u.radial_gradient.c1.y / 65536.f, + paint.u.radial_gradient.r1 / 65536.f); + } + break; + case FT_COLR_PAINTFORMAT_SWEEP_GRADIENT: + { + hb_color_line_t cl = { + &paint.u.linear_gradient.colorline, + _hb_ft_color_line_get_color_stops, c, + _hb_ft_color_line_get_extend, nullptr + }; + + c->funcs->sweep_gradient (c->data, &cl, + paint.u.sweep_gradient.center.x / 65536.f, + paint.u.sweep_gradient.center.y / 65536.f, + (paint.u.sweep_gradient.start_angle / 65536.f + 1) * HB_PI, + (paint.u.sweep_gradient.end_angle / 65536.f + 1) * HB_PI); + } + break; + case FT_COLR_PAINTFORMAT_GLYPH: + { + c->funcs->push_inverse_root_transform (c->data, c->font); + c->ft_font->lock.unlock (); + c->funcs->push_clip_glyph (c->data, paint.u.glyph.glyphID, c->font); + c->ft_font->lock.lock (); + c->funcs->push_root_transform (c->data, c->font); + c->recurse (paint.u.glyph.paint); + c->funcs->pop_transform (c->data); + c->funcs->pop_clip (c->data); + c->funcs->pop_transform (c->data); + } + break; + case FT_COLR_PAINTFORMAT_COLR_GLYPH: + { + hb_codepoint_t gid = paint.u.colr_glyph.glyphID; + + if (unlikely (c->current_glyphs.has (gid))) + return; + + c->current_glyphs.add (gid); + + c->funcs->push_inverse_root_transform (c->data, c->font); + c->ft_font->lock.unlock (); + if (c->funcs->color_glyph (c->data, gid, c->font)) + { + c->ft_font->lock.lock (); + c->funcs->pop_transform (c->data); + c->current_glyphs.del (gid); + return; + } + c->ft_font->lock.lock (); + c->funcs->pop_transform (c->data); + + FT_OpaquePaint other_paint = {0}; + if (FT_Get_Color_Glyph_Paint (ft_face, gid, + FT_COLOR_NO_ROOT_TRANSFORM, + &other_paint)) + { + bool has_clip_box; + FT_ClipBox clip_box; + has_clip_box = FT_Get_Color_Glyph_ClipBox (ft_face, paint.u.colr_glyph.glyphID, &clip_box); + + if (has_clip_box) + { + /* The FreeType ClipBox is in scaled coordinates, whereas we need + * unscaled clipbox here. Oh well... + */ + + float upem = c->font->face->get_upem (); + float xscale = upem / (c->font->x_scale ? c->font->x_scale : upem); + float yscale = upem / (c->font->y_scale ? c->font->y_scale : upem); + + c->funcs->push_clip_rectangle (c->data, + clip_box.bottom_left.x * xscale, + clip_box.bottom_left.y * yscale, + clip_box.top_right.x * xscale, + clip_box.top_right.y * yscale); + } + + c->recurse (other_paint); + + if (has_clip_box) + c->funcs->pop_clip (c->data); + + c->current_glyphs.del (gid); + } + } + break; + case FT_COLR_PAINTFORMAT_TRANSFORM: + { + c->funcs->push_transform (c->data, + paint.u.transform.affine.xx / 65536.f, + paint.u.transform.affine.yx / 65536.f, + paint.u.transform.affine.xy / 65536.f, + paint.u.transform.affine.yy / 65536.f, + paint.u.transform.affine.dx / 65536.f, + paint.u.transform.affine.dy / 65536.f); + c->recurse (paint.u.transform.paint); + c->funcs->pop_transform (c->data); + } + break; + case FT_COLR_PAINTFORMAT_TRANSLATE: + { + float dx = paint.u.translate.dx / 65536.f; + float dy = paint.u.translate.dy / 65536.f; + + bool p1 = c->funcs->push_translate (c->data, dx, dy); + c->recurse (paint.u.translate.paint); + if (p1) c->funcs->pop_transform (c->data); + } + break; + case FT_COLR_PAINTFORMAT_SCALE: + { + float dx = paint.u.scale.center_x / 65536.f; + float dy = paint.u.scale.center_y / 65536.f; + float sx = paint.u.scale.scale_x / 65536.f; + float sy = paint.u.scale.scale_y / 65536.f; + + bool p1 = c->funcs->push_translate (c->data, +dx, +dy); + bool p2 = c->funcs->push_scale (c->data, sx, sy); + bool p3 = c->funcs->push_translate (c->data, -dx, -dy); + c->recurse (paint.u.scale.paint); + if (p3) c->funcs->pop_transform (c->data); + if (p2) c->funcs->pop_transform (c->data); + if (p1) c->funcs->pop_transform (c->data); + } + break; + case FT_COLR_PAINTFORMAT_ROTATE: + { + float dx = paint.u.rotate.center_x / 65536.f; + float dy = paint.u.rotate.center_y / 65536.f; + float a = paint.u.rotate.angle / 65536.f; + + bool p1 = c->funcs->push_translate (c->data, +dx, +dy); + bool p2 = c->funcs->push_rotate (c->data, a); + bool p3 = c->funcs->push_translate (c->data, -dx, -dy); + c->recurse (paint.u.rotate.paint); + if (p3) c->funcs->pop_transform (c->data); + if (p2) c->funcs->pop_transform (c->data); + if (p1) c->funcs->pop_transform (c->data); + } + break; + case FT_COLR_PAINTFORMAT_SKEW: + { + float dx = paint.u.skew.center_x / 65536.f; + float dy = paint.u.skew.center_y / 65536.f; + float sx = paint.u.skew.x_skew_angle / 65536.f; + float sy = paint.u.skew.y_skew_angle / 65536.f; + + bool p1 = c->funcs->push_translate (c->data, +dx, +dy); + bool p2 = c->funcs->push_skew (c->data, sx, sy); + bool p3 = c->funcs->push_translate (c->data, -dx, -dy); + c->recurse (paint.u.skew.paint); + if (p3) c->funcs->pop_transform (c->data); + if (p2) c->funcs->pop_transform (c->data); + if (p1) c->funcs->pop_transform (c->data); + } + break; + case FT_COLR_PAINTFORMAT_COMPOSITE: + { + c->recurse (paint.u.composite.backdrop_paint); + c->funcs->push_group (c->data); + c->recurse (paint.u.composite.source_paint); + c->funcs->pop_group (c->data, _hb_ft_paint_composite_mode (paint.u.composite.composite_mode)); + } + break; + + case FT_COLR_PAINT_FORMAT_MAX: break; + default: HB_FALLTHROUGH; + case FT_COLR_PAINTFORMAT_UNSUPPORTED: break; + } +} + + +static bool +hb_ft_paint_glyph_colr (hb_font_t *font, + void *font_data, + hb_codepoint_t gid, + hb_paint_funcs_t *paint_funcs, void *paint_data, + unsigned int palette_index, + hb_color_t foreground, + void *user_data) +{ + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + FT_Face ft_face = ft_font->ft_face; + + /* Face is locked. */ + + FT_Error error; + FT_Color* palette; + FT_LayerIterator iterator; + + FT_Bool have_layers; + FT_UInt layer_glyph_index; + FT_UInt layer_color_index; + + error = FT_Palette_Select(ft_face, palette_index, &palette); + if (error) + palette = NULL; + + /* COLRv1 */ + FT_OpaquePaint paint = {0}; + if (FT_Get_Color_Glyph_Paint (ft_face, gid, + FT_COLOR_NO_ROOT_TRANSFORM, + &paint)) + { + hb_ft_paint_context_t c (ft_font, font, + paint_funcs, paint_data, + palette, palette_index, foreground); + c.current_glyphs.add (gid); + + bool is_bounded = true; + FT_ClipBox clip_box; + if (FT_Get_Color_Glyph_ClipBox (ft_face, gid, &clip_box)) + { + c.funcs->push_clip_rectangle (c.data, + clip_box.bottom_left.x + + roundf (hb_min (font->slant_xy * clip_box.bottom_left.y, + font->slant_xy * clip_box.top_left.y)), + clip_box.bottom_left.y, + clip_box.top_right.x + + roundf (hb_max (font->slant_xy * clip_box.bottom_right.y, + font->slant_xy * clip_box.top_right.y)), + clip_box.top_right.y); + } + else + { + + auto *extents_funcs = hb_paint_extents_get_funcs (); + hb_paint_extents_context_t extents_data; + hb_ft_paint_context_t ce (ft_font, font, + extents_funcs, &extents_data, + palette, palette_index, foreground); + ce.current_glyphs.add (gid); + ce.funcs->push_root_transform (ce.data, font); + ce.recurse (paint); + ce.funcs->pop_transform (ce.data); + hb_extents_t extents = extents_data.get_extents (); + is_bounded = extents_data.is_bounded (); + + c.funcs->push_clip_rectangle (c.data, + extents.xmin, + extents.ymin, + extents.xmax, + extents.ymax); + } + + c.funcs->push_root_transform (c.data, font); + + if (is_bounded) + c.recurse (paint); + + c.funcs->pop_transform (c.data); + c.funcs->pop_clip (c.data); + + return true; + } + + /* COLRv0 */ + iterator.p = NULL; + have_layers = FT_Get_Color_Glyph_Layer(ft_face, + gid, + &layer_glyph_index, + &layer_color_index, + &iterator); + + if (palette && have_layers) + { + do + { + hb_bool_t is_foreground = true; + hb_color_t color = foreground; + + if ( layer_color_index != 0xFFFF ) + { + FT_Color layer_color = palette[layer_color_index]; + color = HB_COLOR (layer_color.blue, + layer_color.green, + layer_color.red, + layer_color.alpha); + is_foreground = false; + } + + ft_font->lock.unlock (); + paint_funcs->push_clip_glyph (paint_data, layer_glyph_index, font); + ft_font->lock.lock (); + paint_funcs->color (paint_data, is_foreground, color); + paint_funcs->pop_clip (paint_data); + + } while (FT_Get_Color_Glyph_Layer(ft_face, + gid, + &layer_glyph_index, + &layer_color_index, + &iterator)); + return true; + } + + return false; +} + + +#endif /* HB_FT_COLR_HH */ diff --git a/libs/harfbuzz/src/hb-ft.cc b/libs/harfbuzz/src/hb-ft.cc index 1626b9a15..c305df19a 100644 --- a/libs/harfbuzz/src/hb-ft.cc +++ b/libs/harfbuzz/src/hb-ft.cc @@ -33,17 +33,23 @@ #include "hb-ft.h" +#include "hb-cache.hh" #include "hb-draw.hh" #include "hb-font.hh" #include "hb-machinery.hh" -#include "hb-cache.hh" #include "hb-ot-os2-table.hh" #include "hb-ot-shaper-arabic-pua.hh" +#include "hb-paint.hh" +#include FT_MODULE_H #include FT_ADVANCES_H #include FT_MULTIPLE_MASTERS_H #include FT_OUTLINE_H #include FT_TRUETYPE_TABLES_H +#include FT_SYNTHESIS_H +#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21300 +#include FT_COLOR_H +#endif /** @@ -89,7 +95,7 @@ struct hb_ft_font_t bool unref; /* Whether to destroy ft_face when done. */ bool transform; /* Whether to apply FT_Face's transform. */ - mutable hb_mutex_t lock; + mutable hb_mutex_t lock; /* Protects members below. */ FT_Face ft_face; mutable unsigned cached_serial; mutable hb_ft_advance_cache_t advance_cache; @@ -109,7 +115,7 @@ _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref) ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING; ft_font->cached_serial = (unsigned) -1; - ft_font->advance_cache.init (); + new (&ft_font->advance_cache) hb_ft_advance_cache_t; return ft_font; } @@ -125,8 +131,6 @@ _hb_ft_font_destroy (void *data) { hb_ft_font_t *ft_font = (hb_ft_font_t *) data; - ft_font->advance_cache.fini (); - if (ft_font->unref) _hb_ft_face_destroy (ft_font->ft_face); @@ -157,9 +161,9 @@ static void _hb_ft_hb_font_changed (hb_font_t *font, FT_Face ft_face) { #ifdef HAVE_FT_GET_TRANSFORM /* Bitmap font, eg. bitmap color emoji. */ - /* TODO Pick largest size? */ - int x_scale = ft_face->available_sizes[0].x_ppem; - int y_scale = ft_face->available_sizes[0].y_ppem; + /* Pick largest size? */ + int x_scale = ft_face->available_sizes[ft_face->num_fixed_sizes - 1].x_ppem; + int y_scale = ft_face->available_sizes[ft_face->num_fixed_sizes - 1].y_ppem; FT_Set_Char_Size (ft_face, x_scale, y_scale, 0, 0); @@ -221,8 +225,11 @@ _hb_ft_hb_font_check_changed (hb_font_t *font, * * Sets the FT_Load_Glyph load flags for the specified #hb_font_t. * - * For more information, see - * https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#ft_load_xxx + * For more information, see + * + * + * This function works with #hb_font_t objects created by + * hb_ft_font_create() or hb_ft_font_create_referenced(). * * Since: 1.0.5 **/ @@ -246,10 +253,13 @@ hb_ft_font_set_load_flags (hb_font_t *font, int load_flags) * * Fetches the FT_Load_Glyph load flags of the specified #hb_font_t. * - * For more information, see - * https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#ft_load_xxx + * For more information, see + * * - * Return value: FT_Load_Glyph flags found + * This function works with #hb_font_t objects created by + * hb_ft_font_create() or hb_ft_font_create_referenced(). + * + * Return value: FT_Load_Glyph flags found, or 0 * * Since: 1.0.5 **/ @@ -271,6 +281,9 @@ hb_ft_font_get_load_flags (hb_font_t *font) * Fetches the FT_Face associated with the specified #hb_font_t * font object. * + * This function works with #hb_font_t objects created by + * hb_ft_font_create() or hb_ft_font_create_referenced(). + * * Return value: (nullable): the FT_Face found or `NULL` * * Since: 0.9.2 @@ -290,8 +303,13 @@ hb_ft_font_get_face (hb_font_t *font) * hb_ft_font_lock_face: (skip) * @font: #hb_font_t to work upon * - * Gets the FT_Face associated with @font, This face will be kept around until - * you call hb_ft_font_unlock_face(). + * Gets the FT_Face associated with @font. + * + * This face will be kept around and access to the FT_Face object + * from other HarfBuzz API wil be blocked until you call hb_ft_font_unlock_face(). + * + * This function works with #hb_font_t objects created by + * hb_ft_font_create() or hb_ft_font_create_referenced(). * * Return value: (nullable) (transfer none): the FT_Face associated with @font or `NULL` * Since: 2.6.5 @@ -431,6 +449,7 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data, void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + hb_position_t *orig_first_advance = first_advance; hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; int load_flags = ft_font->load_flags; @@ -441,6 +460,7 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data, FT_Matrix matrix; FT_Get_Transform (ft_face, &matrix, nullptr); x_mult = sqrtf ((float)matrix.xx * matrix.xx + (float)matrix.xy * matrix.xy) / 65536.f; + x_mult *= font->x_scale < 0 ? -1 : +1; } else #endif @@ -459,13 +479,29 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data, else { FT_Get_Advance (ft_face, glyph, load_flags, &v); + /* Work around bug that FreeType seems to return negative advance + * for variable-set fonts if x_scale is negative! */ + v = abs (v); + v = (int) (v * x_mult + (1<<9)) >> 10; ft_font->advance_cache.set (glyph, v); } - *first_advance = (int) (v * x_mult + (1<<9)) >> 10; + *first_advance = v; first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } + + if (font->x_strength && !font->embolden_in_place) + { + /* Emboldening. */ + hb_position_t x_strength = font->x_scale >= 0 ? font->x_strength : -font->x_strength; + first_advance = orig_first_advance; + for (unsigned int i = 0; i < count; i++) + { + *first_advance += *first_advance ? x_strength : 0; + first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); + } + } } #ifndef HB_NO_VERTICAL @@ -485,6 +521,7 @@ hb_ft_get_glyph_v_advance (hb_font_t *font, FT_Matrix matrix; FT_Get_Transform (ft_font->ft_face, &matrix, nullptr); y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f; + y_mult *= font->y_scale < 0 ? -1 : +1; } else #endif @@ -500,7 +537,8 @@ hb_ft_get_glyph_v_advance (hb_font_t *font, /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates * have a Y growing upward. Hence the extra negation. */ - return (-v + (1<<9)) >> 10; + hb_position_t y_strength = font->y_scale >= 0 ? font->y_strength : -font->y_strength; + return ((-v + (1<<9)) >> 10) + (font->embolden_in_place ? 0 : y_strength); } #endif @@ -523,7 +561,9 @@ hb_ft_get_glyph_v_origin (hb_font_t *font, FT_Matrix matrix; FT_Get_Transform (ft_face, &matrix, nullptr); x_mult = sqrtf ((float)matrix.xx * matrix.xx + (float)matrix.xy * matrix.xy) / 65536.f; + x_mult *= font->x_scale < 0 ? -1 : +1; y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f; + y_mult *= font->y_scale < 0 ? -1 : +1; } else #endif @@ -578,13 +618,16 @@ hb_ft_get_glyph_extents (hb_font_t *font, hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; float x_mult, y_mult; + float slant_xy = font->slant_xy; #ifdef HAVE_FT_GET_TRANSFORM if (ft_font->transform) { FT_Matrix matrix; FT_Get_Transform (ft_face, &matrix, nullptr); x_mult = sqrtf ((float)matrix.xx * matrix.xx + (float)matrix.xy * matrix.xy) / 65536.f; + x_mult *= font->x_scale < 0 ? -1 : +1; y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f; + y_mult *= font->y_scale < 0 ? -1 : +1; } else #endif @@ -596,10 +639,40 @@ hb_ft_get_glyph_extents (hb_font_t *font, if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) return false; - extents->x_bearing = (hb_position_t) (x_mult * ft_face->glyph->metrics.horiBearingX); - extents->y_bearing = (hb_position_t) (y_mult * ft_face->glyph->metrics.horiBearingY); - extents->width = (hb_position_t) (x_mult * ft_face->glyph->metrics.width); - extents->height = (hb_position_t) (y_mult * -ft_face->glyph->metrics.height); + /* Copied from hb_font_t::scale_glyph_extents. */ + + float x1 = x_mult * ft_face->glyph->metrics.horiBearingX; + float y1 = y_mult * ft_face->glyph->metrics.horiBearingY; + float x2 = x1 + x_mult * ft_face->glyph->metrics.width; + float y2 = y1 + y_mult * -ft_face->glyph->metrics.height; + + /* Apply slant. */ + if (slant_xy) + { + x1 += hb_min (y1 * slant_xy, y2 * slant_xy); + x2 += hb_max (y1 * slant_xy, y2 * slant_xy); + } + + extents->x_bearing = floorf (x1); + extents->y_bearing = floorf (y1); + extents->width = ceilf (x2) - extents->x_bearing; + extents->height = ceilf (y2) - extents->y_bearing; + + if (font->x_strength || font->y_strength) + { + /* Y */ + int y_shift = font->y_strength; + if (font->y_scale < 0) y_shift = -y_shift; + extents->y_bearing += y_shift; + extents->height -= y_shift; + + /* X */ + int x_shift = font->x_strength; + if (font->x_scale < 0) x_shift = -x_shift; + if (font->embolden_in_place) + extents->x_bearing -= x_shift / 2; + extents->width += x_shift; + } return true; } @@ -700,6 +773,7 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED, FT_Matrix matrix; FT_Get_Transform (ft_face, &matrix, nullptr); y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f; + y_mult *= font->y_scale < 0 ? -1 : +1; } else #endif @@ -721,7 +795,7 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED, metrics->line_gap = ft_face->size->metrics.height - (metrics->ascender - metrics->descender); } - metrics->ascender = (hb_position_t) (y_mult * metrics->ascender); + metrics->ascender = (hb_position_t) (y_mult * (metrics->ascender + font->y_strength)); metrics->descender = (hb_position_t) (y_mult * metrics->descender); metrics->line_gap = (hb_position_t) (y_mult * metrics->line_gap); @@ -773,11 +847,11 @@ _hb_ft_cubic_to (const FT_Vector *control1, } static void -hb_ft_get_glyph_shape (hb_font_t *font HB_UNUSED, - void *font_data, - hb_codepoint_t glyph, - hb_draw_funcs_t *draw_funcs, void *draw_data, - void *user_data HB_UNUSED) +hb_ft_draw_glyph (hb_font_t *font, + void *font_data, + hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, void *draw_data, + void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; hb_lock_t lock (ft_font->lock); @@ -801,12 +875,129 @@ hb_ft_get_glyph_shape (hb_font_t *font HB_UNUSED, hb_draw_session_t draw_session (draw_funcs, draw_data, font->slant_xy); + /* Embolden */ + if (font->x_strength || font->y_strength) + { + FT_Outline_EmboldenXY (&ft_face->glyph->outline, font->x_strength, font->y_strength); + + int x_shift = 0; + int y_shift = 0; + if (font->embolden_in_place) + { + /* Undo the FreeType shift. */ + x_shift = -font->x_strength / 2; + y_shift = 0; + if (font->y_scale < 0) y_shift = -font->y_strength; + } + else + { + /* FreeType applied things in the wrong direction for negative scale; fix up. */ + if (font->x_scale < 0) x_shift = -font->x_strength; + if (font->y_scale < 0) y_shift = -font->y_strength; + } + if (x_shift || y_shift) + { + auto &outline = ft_face->glyph->outline; + for (auto &point : hb_iter (outline.points, outline.contours[outline.n_contours - 1] + 1)) + { + point.x += x_shift; + point.y += y_shift; + } + } + } + + FT_Outline_Decompose (&ft_face->glyph->outline, &outline_funcs, &draw_session); } #endif +#ifndef HB_NO_PAINT +#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21300 + +#include "hb-ft-colr.hh" + +static void +hb_ft_paint_glyph (hb_font_t *font, + void *font_data, + hb_codepoint_t gid, + hb_paint_funcs_t *paint_funcs, void *paint_data, + unsigned int palette_index, + hb_color_t foreground, + void *user_data) +{ + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + hb_lock_t lock (ft_font->lock); + FT_Face ft_face = ft_font->ft_face; + + /* We release the lock before calling into glyph callbacks, such that + * eg. draw API can call back into the face.*/ + + if (unlikely (FT_Load_Glyph (ft_face, gid, + ft_font->load_flags | FT_LOAD_COLOR))) + return; + + if (ft_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) + { + if (hb_ft_paint_glyph_colr (font, font_data, gid, + paint_funcs, paint_data, + palette_index, foreground, + user_data)) + return; + + /* Simple outline. */ + ft_font->lock.unlock (); + paint_funcs->push_clip_glyph (paint_data, gid, font); + ft_font->lock.lock (); + paint_funcs->color (paint_data, true, foreground); + paint_funcs->pop_clip (paint_data); + + return; + } + + auto *glyph = ft_face->glyph; + if (glyph->format == FT_GLYPH_FORMAT_BITMAP) + { + auto &bitmap = glyph->bitmap; + if (bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) + { + if (bitmap.pitch != (signed) bitmap.width * 4) + return; + + ft_font->lock.unlock (); + + hb_blob_t *blob = hb_blob_create ((const char *) bitmap.buffer, + bitmap.pitch * bitmap.rows, + HB_MEMORY_MODE_DUPLICATE, + nullptr, nullptr); + + hb_glyph_extents_t extents; + if (!hb_font_get_glyph_extents (font, gid, &extents)) + goto out; + + if (!paint_funcs->image (paint_data, + blob, + bitmap.width, + bitmap.rows, + HB_PAINT_IMAGE_FORMAT_BGRA, + font->slant_xy, + &extents)) + { + /* TODO Try a forced outline load and paint? */ + } + + out: + hb_blob_destroy (blob); + ft_font->lock.lock (); + } + + return; + } +} +#endif +#endif + static inline void free_static_ft_funcs (); @@ -840,7 +1031,13 @@ static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t= 21300 + hb_font_funcs_set_paint_glyph_func (funcs, hb_ft_paint_glyph, nullptr, nullptr); +#endif #endif hb_font_funcs_make_immutable (funcs); @@ -908,6 +1105,45 @@ _hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data buffer, hb_free); } +static unsigned +_hb_ft_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) +{ + FT_Face ft_face = (FT_Face) user_data; + + FT_ULong population = 0; + FT_Sfnt_Table_Info (ft_face, + 0, // table_index; ignored + nullptr, + &population); + + if (!table_count) + return population; + else + *table_count = 0; + + if (unlikely (start_offset >= population)) + return population; + + unsigned end_offset = hb_min (start_offset + *table_count, (unsigned) population); + if (unlikely (end_offset < start_offset)) + return population; + + *table_count = end_offset - start_offset; + for (unsigned i = start_offset; i < end_offset; i++) + { + FT_ULong tag = 0, length; + FT_Sfnt_Table_Info (ft_face, i, &tag, &length); + table_tags[i - start_offset] = tag; + } + + return population; +} + + /** * hb_ft_face_create: * @ft_face: (destroy destroy) (scope notified): FT_Face to work upon @@ -915,13 +1151,17 @@ _hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data * * Creates an #hb_face_t face object from the specified FT_Face. * + * Note that this is using the FT_Face object just to get at the underlying + * font data, and fonts created from the returned #hb_face_t will use the native + * HarfBuzz font implementation, unless you call hb_ft_font_set_funcs() on them. + * * This variant of the function does not provide any life-cycle management. * * Most client programs should use hb_ft_face_create_referenced() - * (or, perhaps, hb_ft_face_create_cached()) instead. + * (or, perhaps, hb_ft_face_create_cached()) instead. * * If you know you have valid reasons not to use hb_ft_face_create_referenced(), - * then it is the client program's responsibility to destroy @ft_face + * then it is the client program's responsibility to destroy @ft_face * after the #hb_face_t face object has been destroyed. * * Return value: (transfer full): the new #hb_face_t face object @@ -945,6 +1185,7 @@ hb_ft_face_create (FT_Face ft_face, hb_blob_destroy (blob); } else { face = hb_face_create_for_tables (_hb_ft_reference_table, ft_face, destroy); + hb_face_set_get_table_tags_func (face, _hb_ft_get_table_tags, ft_face, nullptr); } hb_face_set_index (face, ft_face->face_index); @@ -959,6 +1200,10 @@ hb_ft_face_create (FT_Face ft_face, * * Creates an #hb_face_t face object from the specified FT_Face. * + * Note that this is using the FT_Face object just to get at the underlying + * font data, and fonts created from the returned #hb_face_t will use the native + * HarfBuzz font implementation, unless you call hb_ft_font_set_funcs() on them. + * * This is the preferred variant of the hb_ft_face_create* * function family, because it calls FT_Reference_Face() on @ft_face, * ensuring that @ft_face remains alive as long as the resulting @@ -991,6 +1236,10 @@ hb_ft_face_finalize (void *arg) * * Creates an #hb_face_t face object from the specified FT_Face. * + * Note that this is using the FT_Face object just to get at the underlying + * font data, and fonts created from the returned #hb_face_t will use the native + * HarfBuzz font implementation, unless you call hb_ft_font_set_funcs() on them. + * * This variant of the function caches the newly created #hb_face_t * face object, using the @generic pointer of @ft_face. Subsequent function * calls that are passed the same @ft_face parameter will have the same @@ -1007,7 +1256,7 @@ hb_ft_face_finalize (void *arg) hb_face_t * hb_ft_face_create_cached (FT_Face ft_face) { - if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != (FT_Generic_Finalizer) hb_ft_face_finalize)) + if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != hb_ft_face_finalize)) { if (ft_face->generic.finalizer) ft_face->generic.finalizer (ft_face); @@ -1033,13 +1282,13 @@ hb_ft_face_create_cached (FT_Face ft_face) * This variant of the function does not provide any life-cycle management. * * Most client programs should use hb_ft_font_create_referenced() - * instead. + * instead. * * If you know you have valid reasons not to use hb_ft_font_create_referenced(), - * then it is the client program's responsibility to destroy @ft_face + * then it is the client program's responsibility to destroy @ft_face * after the #hb_font_t font object has been destroyed. * - * HarfBuzz will use the @destroy callback on the #hb_font_t font object + * HarfBuzz will use the @destroy callback on the #hb_font_t font object * if it is supplied when you use this function. However, even if @destroy * is provided, it is the client program's responsibility to destroy @ft_face, * and it is the client program's responsibility to ensure that @ft_face is @@ -1184,6 +1433,24 @@ hb_ft_font_create_referenced (FT_Face ft_face) return hb_ft_font_create (ft_face, _hb_ft_face_destroy); } + +static void * _hb_ft_alloc (FT_Memory memory, long size) +{ return hb_malloc (size); } + +static void _hb_ft_free (FT_Memory memory, void *block) +{ hb_free (block); } + +static void * _hb_ft_realloc (FT_Memory memory, long cur_size, long new_size, void *block) +{ return hb_realloc (block, new_size); } + +static FT_MemoryRec_ m = +{ + nullptr, + _hb_ft_alloc, + _hb_ft_free, + _hb_ft_realloc +}; + static inline void free_static_ft_library (); static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t, @@ -1192,16 +1459,19 @@ static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_tgeneric.data); +} + +static void +destroy_ft_library (void *arg) +{ + FT_Done_Library ((FT_Library) arg); +} + +/** + * hb_ft_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 FreeType 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_ft_face_create_from_file_or_fail (const char *file_name, + unsigned int index) +{ + FT_Library ft_library = reference_ft_library (); + if (unlikely (!ft_library)) + { + DEBUG_MSG (FT, ft_library, "reference_ft_library failed"); + return nullptr; + } + + FT_Face ft_face; + if (unlikely (FT_New_Face (ft_library, + file_name, + index, + &ft_face))) + return nullptr; + + hb_face_t *face = hb_ft_face_create_referenced (ft_face); + FT_Done_Face (ft_face); + + ft_face->generic.data = ft_library; + ft_face->generic.finalizer = finalize_ft_library; + + if (hb_face_is_immutable (face)) + return nullptr; + + return face; } static void @@ -1241,10 +1578,14 @@ _release_blob (void *arg) * created with hb_face_create(), and therefore was not * initially configured to use FreeType font functions. * - * An #hb_face_t face object created with hb_ft_face_create() + * An #hb_font_t object created with hb_ft_font_create() * is preconfigured for FreeType font functions and does not * require this function to be used. * + * Note that if you modify the underlying #hb_font_t after + * calling this function, you need to call hb_ft_hb_font_changed() + * to update the underlying FT_Face. + * * Note: Internally, this function creates an FT_Face. * * @@ -1259,31 +1600,40 @@ hb_ft_font_set_funcs (hb_font_t *font) if (unlikely (!blob_length)) DEBUG_MSG (FT, font, "Font face has empty blob"); - FT_Face ft_face = nullptr; - FT_Error err = FT_New_Memory_Face (get_ft_library (), - (const FT_Byte *) blob_data, - blob_length, - hb_face_get_index (font->face), - &ft_face); + FT_Library ft_library = reference_ft_library (); + if (unlikely (!ft_library)) + { + hb_blob_destroy (blob); + DEBUG_MSG (FT, font, "reference_ft_library failed"); + return; + } - if (unlikely (err)) { + FT_Face ft_face = nullptr; + if (unlikely (FT_New_Memory_Face (ft_library, + (const FT_Byte *) blob_data, + blob_length, + hb_face_get_index (font->face), + &ft_face))) + { hb_blob_destroy (blob); - DEBUG_MSG (FT, font, "Font face FT_New_Memory_Face() failed"); + DEBUG_MSG (FT, font, "FT_New_Memory_Face() failed"); return; } if (FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL)) FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE); - + // Hook the blob to the FT_Face ft_face->generic.data = blob; ft_face->generic.finalizer = _release_blob; + // And the FT_Library to the blob + hb_blob_set_user_data (blob, &ft_library_key, ft_library, destroy_ft_library, true); + _hb_ft_font_set_funcs (font, ft_face, true); hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING); _hb_ft_hb_font_changed (font, ft_face); } - #endif diff --git a/libs/harfbuzz/src/hb-ft.h b/libs/harfbuzz/src/hb-ft.h index 6a8a7abe8..8cf14dc39 100644 --- a/libs/harfbuzz/src/hb-ft.h +++ b/libs/harfbuzz/src/hb-ft.h @@ -84,6 +84,9 @@ hb_ft_face_create_cached (FT_Face ft_face); HB_EXTERN hb_face_t * hb_ft_face_create_referenced (FT_Face ft_face); +HB_EXTERN hb_face_t * +hb_ft_face_create_from_file_or_fail (const char *file_name, + unsigned int index); /* * hb-font from ft-face. diff --git a/libs/harfbuzz/src/hb-geometry.hh b/libs/harfbuzz/src/hb-geometry.hh new file mode 100644 index 000000000..7777ff9ac --- /dev/null +++ b/libs/harfbuzz/src/hb-geometry.hh @@ -0,0 +1,284 @@ +/* + * Copyright © 2022 Behdad Esfahbod + * + * 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. + */ +#ifndef HB_GEOMETRY_HH +#define HB_GEOMETRY_HH + +#include "hb.hh" + + +struct hb_extents_t +{ + hb_extents_t () {} + hb_extents_t (float xmin, float ymin, float xmax, float ymax) : + xmin (xmin), ymin (ymin), xmax (xmax), ymax (ymax) {} + + bool is_empty () const { return xmin >= xmax || ymin >= ymax; } + bool is_void () const { return xmin > xmax; } + + void union_ (const hb_extents_t &o) + { + xmin = hb_min (xmin, o.xmin); + ymin = hb_min (ymin, o.ymin); + xmax = hb_max (xmax, o.xmax); + ymax = hb_max (ymax, o.ymax); + } + + void intersect (const hb_extents_t &o) + { + xmin = hb_max (xmin, o.xmin); + ymin = hb_max (ymin, o.ymin); + xmax = hb_min (xmax, o.xmax); + ymax = hb_min (ymax, o.ymax); + } + + void + add_point (float x, float y) + { + if (unlikely (is_void ())) + { + xmin = xmax = x; + ymin = ymax = y; + } + else + { + xmin = hb_min (xmin, x); + ymin = hb_min (ymin, y); + xmax = hb_max (xmax, x); + ymax = hb_max (ymax, y); + } + } + + float xmin = 0.f; + float ymin = 0.f; + float xmax = -1.f; + float ymax = -1.f; +}; + +struct hb_transform_t +{ + hb_transform_t () {} + hb_transform_t (float xx, float yx, + float xy, float yy, + float x0, float y0) : + xx (xx), yx (yx), xy (xy), yy (yy), x0 (x0), y0 (y0) {} + + void multiply (const hb_transform_t &o) + { + /* Copied from cairo, with "o" being "a" there and "this" being "b" there. */ + hb_transform_t r; + + r.xx = o.xx * xx + o.yx * xy; + r.yx = o.xx * yx + o.yx * yy; + + r.xy = o.xy * xx + o.yy * xy; + r.yy = o.xy * yx + o.yy * yy; + + r.x0 = o.x0 * xx + o.y0 * xy + x0; + r.y0 = o.x0 * yx + o.y0 * yy + y0; + + *this = r; + } + + void transform_distance (float &dx, float &dy) const + { + float new_x = xx * dx + xy * dy; + float new_y = yx * dx + yy * dy; + dx = new_x; + dy = new_y; + } + + void transform_point (float &x, float &y) const + { + transform_distance (x, y); + x += x0; + y += y0; + } + + void transform_extents (hb_extents_t &extents) const + { + float quad_x[4], quad_y[4]; + + quad_x[0] = extents.xmin; + quad_y[0] = extents.ymin; + quad_x[1] = extents.xmin; + quad_y[1] = extents.ymax; + quad_x[2] = extents.xmax; + quad_y[2] = extents.ymin; + quad_x[3] = extents.xmax; + quad_y[3] = extents.ymax; + + extents = hb_extents_t {}; + for (unsigned i = 0; i < 4; i++) + { + transform_point (quad_x[i], quad_y[i]); + extents.add_point (quad_x[i], quad_y[i]); + } + } + + void transform (const hb_transform_t &o) { multiply (o); } + + void translate (float x, float y) + { + if (x == 0.f && y == 0.f) + return; + + x0 += xx * x + xy * y; + y0 += yx * x + yy * y; + } + + void scale (float scaleX, float scaleY) + { + if (scaleX == 1.f && scaleY == 1.f) + return; + + xx *= scaleX; + yx *= scaleX; + xy *= scaleY; + yy *= scaleY; + } + + void rotate (float rotation) + { + if (rotation == 0.f) + return; + + // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L240 + rotation = rotation * HB_PI; + float c; + float s; +#ifdef HAVE_SINCOSF + sincosf (rotation, &s, &c); +#else + c = cosf (rotation); + s = sinf (rotation); +#endif + auto other = hb_transform_t{c, s, -s, c, 0.f, 0.f}; + transform (other); + } + + void skew (float skewX, float skewY) + { + if (skewX == 0.f && skewY == 0.f) + return; + + // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L255 + skewX = skewX * HB_PI; + skewY = skewY * HB_PI; + auto other = hb_transform_t{1.f, + skewY ? tanf (skewY) : 0.f, + skewX ? tanf (skewX) : 0.f, + 1.f, + 0.f, 0.f}; + transform (other); + } + + float xx = 1.f; + float yx = 0.f; + float xy = 0.f; + float yy = 1.f; + float x0 = 0.f; + float y0 = 0.f; +}; + +struct hb_bounds_t +{ + enum status_t { + UNBOUNDED, + BOUNDED, + EMPTY, + }; + + hb_bounds_t (status_t status) : status (status) {} + hb_bounds_t (const hb_extents_t &extents) : + status (extents.is_empty () ? EMPTY : BOUNDED), extents (extents) {} + + void union_ (const hb_bounds_t &o) + { + if (o.status == UNBOUNDED) + status = UNBOUNDED; + else if (o.status == BOUNDED) + { + if (status == EMPTY) + *this = o; + else if (status == BOUNDED) + extents.union_ (o.extents); + } + } + + void intersect (const hb_bounds_t &o) + { + if (o.status == EMPTY) + status = EMPTY; + else if (o.status == BOUNDED) + { + if (status == UNBOUNDED) + *this = o; + else if (status == BOUNDED) + { + extents.intersect (o.extents); + if (extents.is_empty ()) + status = EMPTY; + } + } + } + + status_t status; + hb_extents_t extents; +}; + +struct hb_transform_decomposed_t +{ + float translateX = 0; + float translateY = 0; + float rotation = 0; // in degrees, counter-clockwise + float scaleX = 1; + float scaleY = 1; + float skewX = 0; // in degrees, counter-clockwise + float skewY = 0; // in degrees, counter-clockwise + float tCenterX = 0; + float tCenterY = 0; + + operator bool () const + { + return translateX || translateY || + rotation || + scaleX != 1 || scaleY != 1 || + skewX || skewY || + tCenterX || tCenterY; + } + + hb_transform_t to_transform () const + { + hb_transform_t t; + t.translate (translateX + tCenterX, translateY + tCenterY); + t.rotate (rotation); + t.scale (scaleX, scaleY); + t.skew (-skewX, skewY); + t.translate (-tCenterX, -tCenterY); + return t; + } +}; + + +#endif /* HB_GEOMETRY_HH */ diff --git a/libs/harfbuzz/src/hb-glib.cc b/libs/harfbuzz/src/hb-glib.cc index 8ddc7ebad..1da81696e 100644 --- a/libs/harfbuzz/src/hb-glib.cc +++ b/libs/harfbuzz/src/hb-glib.cc @@ -129,32 +129,9 @@ hb_glib_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED, { #if GLIB_CHECK_VERSION(2,29,12) return g_unichar_compose (a, b, ab); +#else + return false; #endif - - /* We don't ifdef-out the fallback code such that compiler always - * sees it and makes sure it's compilable. */ - - gchar utf8[12]; - gchar *normalized; - int len; - hb_bool_t ret; - - len = g_unichar_to_utf8 (a, utf8); - len += g_unichar_to_utf8 (b, utf8 + len); - normalized = g_utf8_normalize (utf8, len, G_NORMALIZE_NFC); - len = g_utf8_strlen (normalized, -1); - if (unlikely (!len)) - return false; - - if (len == 1) { - *ab = g_utf8_get_char (normalized); - ret = true; - } else { - ret = false; - } - - g_free (normalized); - return ret; } static hb_bool_t @@ -166,55 +143,9 @@ hb_glib_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED, { #if GLIB_CHECK_VERSION(2,29,12) return g_unichar_decompose (ab, a, b); +#else + return false; #endif - - /* We don't ifdef-out the fallback code such that compiler always - * sees it and makes sure it's compilable. */ - - gchar utf8[6]; - gchar *normalized; - int len; - hb_bool_t ret; - - len = g_unichar_to_utf8 (ab, utf8); - normalized = g_utf8_normalize (utf8, len, G_NORMALIZE_NFD); - len = g_utf8_strlen (normalized, -1); - if (unlikely (!len)) - return false; - - if (len == 1) { - *a = g_utf8_get_char (normalized); - *b = 0; - ret = *a != ab; - } else if (len == 2) { - *a = g_utf8_get_char (normalized); - *b = g_utf8_get_char (g_utf8_next_char (normalized)); - /* Here's the ugly part: if ab decomposes to a single character and - * that character decomposes again, we have to detect that and undo - * the second part :-(. */ - gchar *recomposed = g_utf8_normalize (normalized, -1, G_NORMALIZE_NFC); - hb_codepoint_t c = g_utf8_get_char (recomposed); - if (c != ab && c != *a) { - *a = c; - *b = 0; - } - g_free (recomposed); - ret = true; - } else { - /* If decomposed to more than two characters, take the last one, - * and recompose the rest to get the first component. */ - gchar *end = g_utf8_offset_to_pointer (normalized, len - 1); - gchar *recomposed; - *b = g_utf8_get_char (end); - recomposed = g_utf8_normalize (normalized, end - normalized, G_NORMALIZE_NFC); - /* We expect that recomposed has exactly one character now. */ - *a = g_utf8_get_char (recomposed); - g_free (recomposed); - ret = true; - } - - g_free (normalized); - return ret; } diff --git a/libs/harfbuzz/src/hb-gobject-structs.cc b/libs/harfbuzz/src/hb-gobject-structs.cc index ef13f1e96..d66de0b23 100644 --- a/libs/harfbuzz/src/hb-gobject-structs.cc +++ b/libs/harfbuzz/src/hb-gobject-structs.cc @@ -29,7 +29,7 @@ #ifdef HAVE_GOBJECT -/** +/* * SECTION:hb-gobject * @title: hb-gobject * @short_description: GObject integration support @@ -91,6 +91,7 @@ hb_gobject_##name##_get_type () \ HB_DEFINE_OBJECT_TYPE (buffer) HB_DEFINE_OBJECT_TYPE (blob) HB_DEFINE_OBJECT_TYPE (draw_funcs) +HB_DEFINE_OBJECT_TYPE (paint_funcs) HB_DEFINE_OBJECT_TYPE (face) HB_DEFINE_OBJECT_TYPE (font) HB_DEFINE_OBJECT_TYPE (font_funcs) @@ -102,8 +103,12 @@ HB_DEFINE_VALUE_TYPE (feature) HB_DEFINE_VALUE_TYPE (glyph_info) HB_DEFINE_VALUE_TYPE (glyph_position) HB_DEFINE_VALUE_TYPE (segment_properties) +HB_DEFINE_VALUE_TYPE (draw_state) +HB_DEFINE_VALUE_TYPE (color_stop) +HB_DEFINE_VALUE_TYPE (color_line) HB_DEFINE_VALUE_TYPE (user_data_key) +HB_DEFINE_VALUE_TYPE (ot_var_axis_info) HB_DEFINE_VALUE_TYPE (ot_math_glyph_variant) HB_DEFINE_VALUE_TYPE (ot_math_glyph_part) diff --git a/libs/harfbuzz/src/hb-gobject-structs.h b/libs/harfbuzz/src/hb-gobject-structs.h index 3914a2431..b7b5f55ce 100644 --- a/libs/harfbuzz/src/hb-gobject-structs.h +++ b/libs/harfbuzz/src/hb-gobject-structs.h @@ -52,6 +52,10 @@ HB_EXTERN GType hb_gobject_draw_funcs_get_type (void); #define HB_GOBJECT_TYPE_DRAW_FUNCS (hb_gobject_draw_funcs_get_type ()) +HB_EXTERN GType +hb_gobject_paint_funcs_get_type (void); +#define HB_GOBJECT_TYPE_PAINT_FUNCS (hb_gobject_paint_funcs_get_type ()) + HB_EXTERN GType hb_gobject_face_get_type (void); #define HB_GOBJECT_TYPE_FACE (hb_gobject_face_get_type ()) @@ -98,10 +102,26 @@ HB_EXTERN GType hb_gobject_segment_properties_get_type (void); #define HB_GOBJECT_TYPE_SEGMENT_PROPERTIES (hb_gobject_segment_properties_get_type ()) +HB_EXTERN GType +hb_gobject_draw_state_get_type (void); +#define HB_GOBJECT_TYPE_DRAW_STATE (hb_gobject_draw_state_get_type ()) + +HB_EXTERN GType +hb_gobject_color_stop_get_type (void); +#define HB_GOBJECT_TYPE_COLOR_STOP (hb_gobject_color_stop_get_type ()) + +HB_EXTERN GType +hb_gobject_color_line_get_type (void); +#define HB_GOBJECT_TYPE_COLOR_LINE (hb_gobject_color_line_get_type ()) + HB_EXTERN GType hb_gobject_user_data_key_get_type (void); #define HB_GOBJECT_TYPE_USER_DATA_KEY (hb_gobject_user_data_key_get_type ()) +HB_EXTERN GType +hb_gobject_ot_var_axis_info_get_type (void); +#define HB_GOBJECT_TYPE_OT_VAR_AXIS_INFO (hb_gobject_ot_var_axis_info_get_type ()) + HB_EXTERN GType hb_gobject_ot_math_glyph_variant_get_type (void); #define HB_GOBJECT_TYPE_OT_MATH_GLYPH_VARIANT (hb_gobject_ot_math_glyph_variant_get_type ()) diff --git a/libs/harfbuzz/src/hb-graphite2.cc b/libs/harfbuzz/src/hb-graphite2.cc index 4d0e687c7..7ea038622 100644 --- a/libs/harfbuzz/src/hb-graphite2.cc +++ b/libs/harfbuzz/src/hb-graphite2.cc @@ -248,6 +248,21 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED, gr_fref_set_feature_value (fref, features[i].value, feats); } + hb_direction_t direction = buffer->props.direction; + hb_direction_t horiz_dir = hb_script_get_horizontal_direction (buffer->props.script); + /* TODO vertical: + * The only BTT vertical script is Ogham, but it's not clear to me whether OpenType + * Ogham fonts are supposed to be implemented BTT or not. Need to research that + * first. */ + if ((HB_DIRECTION_IS_HORIZONTAL (direction) && + direction != horiz_dir && horiz_dir != HB_DIRECTION_INVALID) || + (HB_DIRECTION_IS_VERTICAL (direction) && + direction != HB_DIRECTION_TTB)) + { + hb_buffer_reverse_clusters (buffer); + direction = HB_DIRECTION_REVERSE (direction); + } + gr_segment *seg = nullptr; const gr_slot *is; unsigned int ci = 0, ic = 0; @@ -261,21 +276,11 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED, for (unsigned int i = 0; i < buffer->len; ++i) chars[i] = buffer->info[i].codepoint; - /* TODO ensure_native_direction. */ - - hb_tag_t script_tag[HB_OT_MAX_TAGS_PER_SCRIPT]; - unsigned int count = HB_OT_MAX_TAGS_PER_SCRIPT; - hb_ot_tags_from_script_and_language (hb_buffer_get_script (buffer), - HB_LANGUAGE_INVALID, - &count, - script_tag, - nullptr, nullptr); - seg = gr_make_seg (nullptr, grface, - count ? script_tag[count - 1] : HB_OT_TAG_DEFAULT_SCRIPT, + HB_TAG_NONE, // https://github.com/harfbuzz/harfbuzz/issues/3439#issuecomment-1442650148 feats, gr_utf32, chars, buffer->len, - 2 | (hb_buffer_get_direction (buffer) == HB_DIRECTION_RTL ? 1 : 0)); + 2 | (direction == HB_DIRECTION_RTL ? 1 : 0)); if (unlikely (!seg)) { if (feats) gr_featureval_destroy (feats); @@ -318,7 +323,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED, #undef ALLOCATE_ARRAY - memset (clusters, 0, sizeof (clusters[0]) * buffer->len); + hb_memset (clusters, 0, sizeof (clusters[0]) * buffer->len); hb_codepoint_t *pg = gids; clusters[0].cluster = buffer->info[0].cluster; @@ -327,7 +332,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED, float yscale = (float) font->y_scale / upem; yscale *= yscale / xscale; unsigned int curradv = 0; - if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction)) + if (HB_DIRECTION_IS_BACKWARD (direction)) { curradv = gr_slot_origin_X(gr_seg_first_slot(seg)) * xscale; clusters[0].advance = gr_seg_advance_X(seg) * xscale - curradv; @@ -356,16 +361,17 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED, c->num_chars = before - c->base_char; c->base_glyph = ic; c->num_glyphs = 0; - if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction)) + if (HB_DIRECTION_IS_BACKWARD (direction)) { c->advance = curradv - gr_slot_origin_X(is) * xscale; curradv -= c->advance; } else { + auto origin_X = gr_slot_origin_X (is) * xscale; c->advance = 0; - clusters[ci].advance += gr_slot_origin_X(is) * xscale - curradv; - curradv += clusters[ci].advance; + clusters[ci].advance += origin_X - curradv; + curradv = origin_X; } ci++; } @@ -375,7 +381,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED, clusters[ci].num_chars = after + 1 - clusters[ci].base_char; } - if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction)) + if (HB_DIRECTION_IS_BACKWARD (direction)) clusters[ci].advance += curradv; else clusters[ci].advance += gr_seg_advance_X(seg) * xscale - curradv; @@ -397,7 +403,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED, unsigned int currclus = UINT_MAX; const hb_glyph_info_t *info = buffer->info; hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, nullptr); - if (!HB_DIRECTION_IS_BACKWARD(buffer->props.direction)) + if (!HB_DIRECTION_IS_BACKWARD (direction)) { curradvx = 0; for (is = gr_seg_first_slot (seg); is; pPos++, ++info, is = gr_slot_next_in_segment (is)) diff --git a/libs/harfbuzz/src/hb-graphite2.h b/libs/harfbuzz/src/hb-graphite2.h index f299da9f7..ee9229b8b 100644 --- a/libs/harfbuzz/src/hb-graphite2.h +++ b/libs/harfbuzz/src/hb-graphite2.h @@ -49,7 +49,8 @@ hb_graphite2_face_get_gr_face (hb_face_t *face); #ifndef HB_DISABLE_DEPRECATED -HB_EXTERN HB_DEPRECATED_FOR (hb_graphite2_face_get_gr_face) gr_font * +HB_DEPRECATED_FOR (hb_graphite2_face_get_gr_face) +HB_EXTERN gr_font * hb_graphite2_font_get_gr_font (hb_font_t *font); #endif diff --git a/libs/harfbuzz/src/hb-icu.cc b/libs/harfbuzz/src/hb-icu.cc index e46401f7a..5d39cc03e 100644 --- a/libs/harfbuzz/src/hb-icu.cc +++ b/libs/harfbuzz/src/hb-icu.cc @@ -31,6 +31,11 @@ #ifdef HAVE_ICU +#pragma GCC diagnostic push + +// https://github.com/harfbuzz/harfbuzz/issues/4915 +#pragma GCC diagnostic ignored "-Wredundant-decls" + #include "hb-icu.h" #include "hb-machinery.hh" @@ -44,7 +49,6 @@ /* ICU extra semicolon, fixed since 65, https://github.com/unicode-org/icu/commit/480bec3 */ #if U_ICU_VERSION_MAJOR_NUM < 65 && (defined(__GNUC__) || defined(__clang__)) #define HB_ICU_EXTRA_SEMI_IGNORED -#pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wextra-semi-stmt" #endif @@ -93,15 +97,16 @@ hb_icu_script_to_script (UScriptCode script) UScriptCode hb_icu_script_from_script (hb_script_t script) { + UScriptCode out = USCRIPT_INVALID_CODE; + if (unlikely (script == HB_SCRIPT_INVALID)) - return USCRIPT_INVALID_CODE; + return out; - unsigned int numScriptCode = 1 + u_getIntPropertyMaxValue (UCHAR_SCRIPT); - for (unsigned int i = 0; i < numScriptCode; i++) - if (unlikely (hb_icu_script_to_script ((UScriptCode) i) == script)) - return (UScriptCode) i; + UErrorCode icu_err = U_ZERO_ERROR; + const unsigned char buf[5] = {HB_UNTAG (script), 0}; + uscript_getCode ((const char *) buf, &out, 1, &icu_err); - return USCRIPT_UNKNOWN; + return out; } @@ -283,8 +288,6 @@ hb_icu_get_unicode_funcs () return static_icu_funcs.get_unconst (); } -#ifdef HB_ICU_EXTRA_SEMI_IGNORED #pragma GCC diagnostic pop -#endif #endif diff --git a/libs/harfbuzz/src/hb-iter.hh b/libs/harfbuzz/src/hb-iter.hh index 1a3ab43de..04d09940a 100644 --- a/libs/harfbuzz/src/hb-iter.hh +++ b/libs/harfbuzz/src/hb-iter.hh @@ -63,6 +63,7 @@ struct hb_iter_t static constexpr bool is_iterator = true; static constexpr bool is_random_access_iterator = false; static constexpr bool is_sorted_iterator = false; + static constexpr bool has_fast_len = false; // Should be checked in combination with is_random_access_iterator. private: /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */ @@ -73,8 +74,10 @@ struct hb_iter_t /* Operators. */ iter_t iter () const { return *thiz(); } iter_t operator + () const { return *thiz(); } - iter_t begin () const { return *thiz(); } - iter_t end () const { return thiz()->__end__ (); } + iter_t _begin () const { return *thiz(); } + iter_t begin () const { return _begin (); } + iter_t _end () const { return thiz()->__end__ (); } + iter_t end () const { return _end (); } explicit operator bool () const { return thiz()->__more__ (); } unsigned len () const { return thiz()->__len__ (); } /* The following can only be enabled if item_t is reference type. Otherwise @@ -118,7 +121,9 @@ struct hb_iter_t #define HB_ITER_USING(Name) \ using item_t = typename Name::item_t; \ + using Name::_begin; \ using Name::begin; \ + using Name::_end; \ using Name::end; \ using Name::get_item_size; \ using Name::is_iterator; \ @@ -168,10 +173,16 @@ struct HB_FUNCOBJ (hb_iter); struct { - template unsigned - operator () (T&& c) const - { return c.len (); } + template auto + impl (T&& c, hb_priority<1>) const HB_RETURN (unsigned, c.len ()) + + template auto + impl (T&& c, hb_priority<0>) const HB_RETURN (unsigned, c.len) + + public: + template auto + operator () (T&& c) const HB_RETURN (unsigned, impl (std::forward (c), hb_prioritize)) } HB_FUNCOBJ (hb_len); @@ -313,6 +324,16 @@ struct hb_is_sink_of (hb_is_source_of(Iter, Item) && Iter::is_sorted_iterator) +struct +{ + template + unsigned operator () (const Iterable &_) const { return hb_len (hb_iter (_)); } + + unsigned operator () (unsigned _) const { return _; } +} +HB_FUNCOBJ (hb_len_of); + /* Range-based 'for' for iterables. */ template f; + mutable hb_reference_wrapper f; }; template @@ -440,14 +461,14 @@ struct hb_filter_iter_t : bool __more__ () const { return bool (it); } void __next__ () { do ++it; while (it && !hb_has (p.get (), hb_get (f.get (), *it))); } void __prev__ () { do --it; while (it && !hb_has (p.get (), hb_get (f.get (), *it))); } - hb_filter_iter_t __end__ () const { return hb_filter_iter_t (it.end (), p, f); } + hb_filter_iter_t __end__ () const { return hb_filter_iter_t (it._end (), p, f); } bool operator != (const hb_filter_iter_t& o) const { return it != o.it; } private: Iter it; - hb_reference_wrapper p; - hb_reference_wrapper f; + mutable hb_reference_wrapper p; + mutable hb_reference_wrapper f; }; template struct hb_filter_iter_factory_t @@ -553,7 +574,7 @@ struct hb_zip_iter_t : void __forward__ (unsigned n) { a += n; b += n; } void __prev__ () { --a; --b; } void __rewind__ (unsigned n) { a -= n; b -= n; } - hb_zip_iter_t __end__ () const { return hb_zip_iter_t (a.end (), b.end ()); } + hb_zip_iter_t __end__ () const { return hb_zip_iter_t (a._end (), b._end ()); } /* Note, we should stop if ANY of the iters reaches end. As such two compare * unequal if both items are unequal, NOT if either is unequal. */ bool operator != (const hb_zip_iter_t& o) const @@ -637,7 +658,7 @@ struct hb_concat_iter_t : } } - hb_concat_iter_t __end__ () const { return hb_concat_iter_t (a.end (), b.end ()); } + hb_concat_iter_t __end__ () const { return hb_concat_iter_t (a._end (), b._end ()); } bool operator != (const hb_concat_iter_t& o) const { return a != o.a @@ -831,7 +852,7 @@ struct template auto operator () (Iterable&& it, unsigned count) const HB_AUTO_RETURN - ( hb_zip (hb_range (count), it) | hb_map (hb_second) ) + ( hb_zip (hb_range (count), it) | hb_map_retains_sorting (hb_second) ) /* Specialization arrays. */ diff --git a/libs/harfbuzz/src/hb-kern.hh b/libs/harfbuzz/src/hb-kern.hh index 9ea945cae..0462a0ea8 100644 --- a/libs/harfbuzz/src/hb-kern.hh +++ b/libs/harfbuzz/src/hb-kern.hh @@ -53,7 +53,7 @@ struct hb_kern_machine_t return; buffer->unsafe_to_concat (); - OT::hb_ot_apply_context_t c (1, font, buffer); + OT::hb_ot_apply_context_t c (1, font, buffer, hb_blob_get_empty ()); c.set_lookup_mask (kern_mask); c.set_lookup_props (OT::LookupFlag::IgnoreMarks); auto &skippy_iter = c.iter_input; @@ -70,7 +70,7 @@ struct hb_kern_machine_t continue; } - skippy_iter.reset (idx, 1); + skippy_iter.reset (idx); unsigned unsafe_to; if (!skippy_iter.next (&unsafe_to)) { diff --git a/libs/harfbuzz/src/hb-limits.hh b/libs/harfbuzz/src/hb-limits.hh new file mode 100644 index 000000000..fbc7bbe76 --- /dev/null +++ b/libs/harfbuzz/src/hb-limits.hh @@ -0,0 +1,112 @@ +/* + * Copyright © 2022 Behdad Esfahbod + * + * 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. + */ + +#ifndef HB_LIMITS_HH +#define HB_LIMITS_HH + +#include "hb.hh" + + +#ifndef HB_BUFFER_MAX_LEN_FACTOR +#define HB_BUFFER_MAX_LEN_FACTOR 64 +#endif +#ifndef HB_BUFFER_MAX_LEN_MIN +#define HB_BUFFER_MAX_LEN_MIN 16384 +#endif +#ifndef HB_BUFFER_MAX_LEN_DEFAULT +#define HB_BUFFER_MAX_LEN_DEFAULT 0x3FFFFFFF /* Shaping more than a billion chars? Let us know! */ +#endif + +#ifndef HB_BUFFER_MAX_OPS_FACTOR +#define HB_BUFFER_MAX_OPS_FACTOR 1024 +#endif +#ifndef HB_BUFFER_MAX_OPS_MIN +#define HB_BUFFER_MAX_OPS_MIN 16384 +#endif +#ifndef HB_BUFFER_MAX_OPS_DEFAULT +#define HB_BUFFER_MAX_OPS_DEFAULT 0x1FFFFFFF /* Shaping more than a billion operations? Let us know! */ +#endif + + +#ifndef HB_MAX_NESTING_LEVEL +#define HB_MAX_NESTING_LEVEL 64 +#endif + + +#ifndef HB_MAX_CONTEXT_LENGTH +#define HB_MAX_CONTEXT_LENGTH 64 +#endif + +#ifndef HB_CLOSURE_MAX_STAGES +/* + * The maximum number of times a lookup can be applied during shaping. + * Used to limit the number of iterations of the closure algorithm. + * This must be larger than the number of times add_gsub_pause() is + * called in a collect_features call of any shaper. + */ +#define HB_CLOSURE_MAX_STAGES 12 +#endif + +#ifndef HB_MAX_SCRIPTS +#define HB_MAX_SCRIPTS 500 +#endif + +#ifndef HB_MAX_LANGSYS +#define HB_MAX_LANGSYS 2000 +#endif + +#ifndef HB_MAX_LANGSYS_FEATURE_COUNT +#define HB_MAX_LANGSYS_FEATURE_COUNT 50000 +#endif + +#ifndef HB_MAX_FEATURE_INDICES +#define HB_MAX_FEATURE_INDICES 1500 +#endif + +#ifndef HB_MAX_LOOKUP_VISIT_COUNT +#define HB_MAX_LOOKUP_VISIT_COUNT 35000 +#endif + +#ifndef HB_MAX_GRAPH_EDGE_COUNT +#define HB_MAX_GRAPH_EDGE_COUNT 2048 +#endif + +#ifndef HB_VAR_COMPOSITE_MAX_AXES +#define HB_VAR_COMPOSITE_MAX_AXES 4096 +#endif + +#ifndef HB_GLYF_MAX_POINTS +#define HB_GLYF_MAX_POINTS 200000 +#endif + +#ifndef HB_CFF_MAX_OPS +#define HB_CFF_MAX_OPS 200000 +#endif + +#ifndef HB_MAX_COMPOSITE_OPERATIONS_PER_GLYPH +#define HB_MAX_COMPOSITE_OPERATIONS_PER_GLYPH 64 +#endif + + +#endif /* HB_LIMITS_HH */ diff --git a/libs/harfbuzz/src/hb-machinery.hh b/libs/harfbuzz/src/hb-machinery.hh index 2571f22e1..ecff94f1b 100644 --- a/libs/harfbuzz/src/hb-machinery.hh +++ b/libs/harfbuzz/src/hb-machinery.hh @@ -34,7 +34,6 @@ #include "hb-dispatch.hh" #include "hb-sanitize.hh" -#include "hb-serialize.hh" /* @@ -136,6 +135,13 @@ static inline Type& StructAfter(TObject &X) /* * Lazy loaders. + * + * The lazy-loaders are thread-safe pointer-like objects that create their + * instead on-demand. They also support access to a "data" object that is + * necessary for creating their instance. The data object, if specified, + * is accessed via pointer math, located at a location before the position + * of the loader itself. This avoids having to store a pointer to data + * for every lazy-loader. Multiple lazy-loaders can access the same data. */ template @@ -174,6 +180,9 @@ struct hb_lazy_loader_t : hb_data_wrapper_t hb_lazy_loader_t >::value Funcs; + hb_lazy_loader_t () = default; + hb_lazy_loader_t (const hb_lazy_loader_t &other) = delete; + void init0 () {} /* Init, when memory is already set to 0. No-op for us. */ void init () { instance.set_relaxed (nullptr); } void fini () { do_destroy (instance.get_acquire ()); init (); } @@ -228,7 +237,8 @@ struct hb_lazy_loader_t : hb_data_wrapper_t bool cmpexch (Stored *current, Stored *value) const { - /* This *must* be called when there are no other threads accessing. */ + /* This function can only be safely called directly if no + * other thread is accessing. */ return this->instance.cmpexch (current, value); } @@ -261,7 +271,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t hb_free (p); } -// private: + private: /* Must only have one pointer. */ hb_atomic_ptr_t instance; }; @@ -271,7 +281,11 @@ struct hb_lazy_loader_t : hb_data_wrapper_t template struct hb_face_lazy_loader_t : hb_lazy_loader_t, - hb_face_t, WheresFace> {}; + hb_face_t, WheresFace> +{ + // Hack; have them here for API parity with hb_table_lazy_loader_t + hb_blob_t *get_blob () { return this->get ()->get_blob (); } +}; template struct hb_table_lazy_loader_t : hb_lazy_loader_t (face); } static void destroy (hb_blob_t *p) { hb_blob_destroy (p); } @@ -297,22 +311,22 @@ struct hb_table_lazy_loader_t : hb_lazy_loader_tget_stored (); } }; -template -struct hb_font_funcs_lazy_loader_t : hb_lazy_loader_t -{ - static void destroy (hb_font_funcs_t *p) - { hb_font_funcs_destroy (p); } - static const hb_font_funcs_t *get_null () - { return hb_font_funcs_get_empty (); } -}; -template -struct hb_unicode_funcs_lazy_loader_t : hb_lazy_loader_t -{ - static void destroy (hb_unicode_funcs_t *p) - { hb_unicode_funcs_destroy (p); } - static const hb_unicode_funcs_t *get_null () - { return hb_unicode_funcs_get_empty (); } -}; +#define HB_DEFINE_TYPE_FUNCS_LAZY_LOADER_T(Type) \ + template \ + struct hb_##Type##_funcs_lazy_loader_t : hb_lazy_loader_t \ + { \ + static void destroy (hb_##Type##_funcs_t *p) \ + { hb_##Type##_funcs_destroy (p); } \ + static const hb_##Type##_funcs_t *get_null () \ + { return hb_##Type##_funcs_get_empty (); } \ + } + +HB_DEFINE_TYPE_FUNCS_LAZY_LOADER_T (font); +HB_DEFINE_TYPE_FUNCS_LAZY_LOADER_T (unicode); +HB_DEFINE_TYPE_FUNCS_LAZY_LOADER_T (draw); +HB_DEFINE_TYPE_FUNCS_LAZY_LOADER_T (paint); + +#undef HB_DEFINE_TYPE_FUNCS_LAZY_LOADER_T #endif /* HB_MACHINERY_HH */ diff --git a/libs/harfbuzz/src/hb-map.cc b/libs/harfbuzz/src/hb-map.cc index 5c5f5de59..0dc9246f1 100644 --- a/libs/harfbuzz/src/hb-map.cc +++ b/libs/harfbuzz/src/hb-map.cc @@ -174,7 +174,7 @@ hb_map_allocation_successful (const hb_map_t *map) * * Allocate a copy of @map. * - * Return value: Newly-allocated map. + * Return value: (transfer full): Newly-allocated map. * * Since: 4.4.0 **/ @@ -182,9 +182,10 @@ hb_map_t * hb_map_copy (const hb_map_t *map) { hb_map_t *copy = hb_map_create (); - if (unlikely (!copy)) return nullptr; - copy->resize (map->population); - hb_copy (*map, *copy); + if (unlikely (copy->in_error ())) + return hb_map_get_empty (); + + *copy = *map; return copy; } @@ -335,9 +336,84 @@ hb_map_is_equal (const hb_map_t *map, * * Since: 4.4.0 **/ -HB_EXTERN unsigned int +unsigned int hb_map_hash (const hb_map_t *map) { return map->hash (); } +/** + * hb_map_update: + * @map: A map + * @other: Another map + * + * Add the contents of @other to @map. + * + * Since: 7.0.0 + **/ +HB_EXTERN void +hb_map_update (hb_map_t *map, + const hb_map_t *other) +{ + map->update (*other); +} + +/** + * hb_map_next: + * @map: A map + * @idx: (inout): Iterator internal state + * @key: (out): Key retrieved + * @value: (out): Value retrieved + * + * Fetches the next key/value pair in @map. + * + * Set @idx to -1 to get started. + * + * If the map is modified during iteration, the behavior is undefined. + * + * The order in which the key/values are returned is undefined. + * + * Return value: `true` if there was a next value, `false` otherwise + * + * Since: 7.0.0 + **/ +hb_bool_t +hb_map_next (const hb_map_t *map, + int *idx, + hb_codepoint_t *key, + hb_codepoint_t *value) +{ + return map->next (idx, key, value); +} + +/** + * hb_map_keys: + * @map: A map + * @keys: A set + * + * Add the keys of @map to @keys. + * + * Since: 7.0.0 + **/ +void +hb_map_keys (const hb_map_t *map, + hb_set_t *keys) +{ + hb_copy (map->keys() , *keys); +} + +/** + * hb_map_values: + * @map: A map + * @values: A set + * + * Add the values of @map to @values. + * + * Since: 7.0.0 + **/ +void +hb_map_values (const hb_map_t *map, + hb_set_t *values) +{ + hb_copy (map->values() , *values); +} diff --git a/libs/harfbuzz/src/hb-map.h b/libs/harfbuzz/src/hb-map.h index 3a067c5c7..0ae171714 100644 --- a/libs/harfbuzz/src/hb-map.h +++ b/libs/harfbuzz/src/hb-map.h @@ -32,6 +32,7 @@ #define HB_MAP_H #include "hb-common.h" +#include "hb-set.h" HB_BEGIN_DECLS @@ -43,7 +44,7 @@ HB_BEGIN_DECLS * * Since: 1.7.7 */ -#define HB_MAP_VALUE_INVALID ((hb_codepoint_t) -1) +#define HB_MAP_VALUE_INVALID HB_CODEPOINT_INVALID /** * hb_map_t: @@ -118,6 +119,24 @@ HB_EXTERN hb_bool_t hb_map_has (const hb_map_t *map, hb_codepoint_t key); +HB_EXTERN void +hb_map_update (hb_map_t *map, + const hb_map_t *other); + +/* Pass -1 in for idx to get started. */ +HB_EXTERN hb_bool_t +hb_map_next (const hb_map_t *map, + int *idx, + hb_codepoint_t *key, + hb_codepoint_t *value); + +HB_EXTERN void +hb_map_keys (const hb_map_t *map, + hb_set_t *keys); + +HB_EXTERN void +hb_map_values (const hb_map_t *map, + hb_set_t *values); HB_END_DECLS diff --git a/libs/harfbuzz/src/hb-map.hh b/libs/harfbuzz/src/hb-map.hh index 8302e3f8c..6c9fb7e63 100644 --- a/libs/harfbuzz/src/hb-map.hh +++ b/libs/harfbuzz/src/hb-map.hh @@ -29,6 +29,8 @@ #include "hb.hh" +#include "hb-set.hh" + /* * hb_hashmap_t @@ -40,13 +42,37 @@ template struct hb_hashmap_t { + static constexpr bool realloc_move = true; + hb_hashmap_t () { init (); } ~hb_hashmap_t () { fini (); } - hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t () { resize (population); hb_copy (o, *this); } - hb_hashmap_t (hb_hashmap_t&& o) : hb_hashmap_t () { hb_swap (*this, o); } - hb_hashmap_t& operator= (const hb_hashmap_t& o) { resize (population); hb_copy (o, *this); return *this; } - hb_hashmap_t& operator= (hb_hashmap_t&& o) { hb_swap (*this, o); return *this; } + hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t () + { + if (unlikely (!o.mask)) return; + + if (item_t::is_trivial) + { + items = (item_t *) hb_malloc (sizeof (item_t) * (o.mask + 1)); + if (unlikely (!items)) + { + successful = false; + return; + } + population = o.population; + occupancy = o.occupancy; + mask = o.mask; + prime = o.prime; + max_chain_length = o.max_chain_length; + memcpy (items, o.items, sizeof (item_t) * (mask + 1)); + return; + } + + alloc (o.population); hb_copy (o, *this); + } + hb_hashmap_t (hb_hashmap_t&& o) noexcept : hb_hashmap_t () { hb_swap (*this, o); } + hb_hashmap_t& operator= (const hb_hashmap_t& o) { reset (); alloc (o.population); hb_copy (o, *this); return *this; } + hb_hashmap_t& operator= (hb_hashmap_t&& o) noexcept { hb_swap (*this, o); return *this; } hb_hashmap_t (std::initializer_list> lst) : hb_hashmap_t () { @@ -58,24 +84,32 @@ struct hb_hashmap_t hb_hashmap_t (const Iterable &o) : hb_hashmap_t () { auto iter = hb_iter (o); - if (iter.is_random_access_iterator) - resize (hb_len (iter)); + if (iter.is_random_access_iterator || iter.has_fast_len) + alloc (hb_len (iter)); hb_copy (iter, *this); } struct item_t { K key; - uint32_t hash : 30; + uint32_t is_real_ : 1; uint32_t is_used_ : 1; - uint32_t is_tombstone_ : 1; + uint32_t hash : 30; V value; + item_t () : key (), + is_real_ (false), is_used_ (false), + hash (0), + value () {} + + // Needed for https://github.com/harfbuzz/harfbuzz/issues/4138 + K& get_key () { return key; } + V& get_value () { return value; } + bool is_used () const { return is_used_; } void set_used (bool is_used) { is_used_ = is_used; } - bool is_tombstone () const { return is_tombstone_; } - void set_tombstone (bool is_tombstone) { is_tombstone_ = is_tombstone; } - bool is_real () const { return is_used_ && !is_tombstone_; } + void set_real (bool is_real) { is_real_ = is_real; } + bool is_real () const { return is_real_; } template @@ -88,36 +122,34 @@ struct hb_hashmap_t return minus_1; }; - void clear () - { - new (std::addressof (key)) K (); - new (std::addressof (value)) V (); - hash = 0; - is_used_ = false; - is_tombstone_ = false; - } - - bool operator == (const K &o) { return hb_deref (key) == hb_deref (o); } - bool operator == (const item_t &o) { return *this == o.key; } + bool operator == (const K &o) const { return hb_deref (key) == hb_deref (o); } + bool operator == (const item_t &o) const { return *this == o.key; } hb_pair_t get_pair() const { return hb_pair_t (key, value); } - hb_pair_t get_pair_ref() const { return hb_pair_t (key, value); } + hb_pair_t get_pair_ref() { return hb_pair_t (key, value); } uint32_t total_hash () const - { return (hash * 31) + hb_hash (value); } + { return (hash * 31u) + hb_hash (value); } + + static constexpr bool is_trivial = hb_is_trivially_constructible(K) && + hb_is_trivially_destructible(K) && + hb_is_trivially_constructible(V) && + hb_is_trivially_destructible(V); }; hb_object_header_t header; bool successful; /* Allocations successful */ + unsigned short max_chain_length; unsigned int population; /* Not including tombstones. */ unsigned int occupancy; /* Including tombstones. */ unsigned int mask; unsigned int prime; item_t *items; - friend void swap (hb_hashmap_t& a, hb_hashmap_t& b) + friend void swap (hb_hashmap_t& a, hb_hashmap_t& b) noexcept { if (unlikely (!a.successful || !b.successful)) return; + hb_swap (a.max_chain_length, b.max_chain_length); hb_swap (a.population, b.population); hb_swap (a.occupancy, b.occupancy); hb_swap (a.mask, b.mask); @@ -129,6 +161,7 @@ struct hb_hashmap_t hb_object_init (this); successful = true; + max_chain_length = 0; population = occupancy = 0; mask = 0; prime = 0; @@ -138,10 +171,12 @@ struct hb_hashmap_t { hb_object_fini (this); - if (likely (items)) { + if (likely (items)) + { unsigned size = mask + 1; - for (unsigned i = 0; i < size; i++) - items[i].~item_t (); + if (!item_t::is_trivial) + for (unsigned i = 0; i < size; i++) + items[i].~item_t (); hb_free (items); items = nullptr; } @@ -156,11 +191,13 @@ struct hb_hashmap_t bool in_error () const { return !successful; } - bool resize (unsigned new_population = 0) + bool alloc (unsigned new_population = 0) { if (unlikely (!successful)) return false; - unsigned int power = hb_bit_storage (hb_max (population, new_population) * 2 + 8); + if (new_population != 0 && (new_population + new_population / 2) < mask) return true; + + unsigned int power = hb_bit_storage (hb_max ((unsigned) population, new_population) * 2 + 8); unsigned int new_size = 1u << power; item_t *new_items = (item_t *) hb_malloc ((size_t) new_size * sizeof (item_t)); if (unlikely (!new_items)) @@ -168,75 +205,178 @@ struct hb_hashmap_t successful = false; return false; } - for (auto &_ : hb_iter (new_items, new_size)) - _.clear (); + if (!item_t::is_trivial) + for (auto &_ : hb_iter (new_items, new_size)) + new (&_) item_t (); + else + hb_memset (new_items, 0, (size_t) new_size * sizeof (item_t)); - unsigned int old_size = mask + 1; + unsigned int old_size = size (); item_t *old_items = items; /* Switch to new, empty, array. */ population = occupancy = 0; mask = new_size - 1; prime = prime_for (power); + max_chain_length = power * 2; items = new_items; /* Insert back old items. */ - if (old_items) - for (unsigned int i = 0; i < old_size; i++) + for (unsigned int i = 0; i < old_size; i++) + { + if (old_items[i].is_real ()) { - if (old_items[i].is_real ()) - { - set_with_hash (old_items[i].key, - old_items[i].hash, - std::move (old_items[i].value)); - } - old_items[i].~item_t (); + set_with_hash (std::move (old_items[i].key), + old_items[i].hash, + std::move (old_items[i].value)); } + } + if (!item_t::is_trivial) + for (unsigned int i = 0; i < old_size; i++) + old_items[i].~item_t (); hb_free (old_items); return true; } + template + bool set_with_hash (KK&& key, uint32_t hash, VV&& value, bool overwrite = true) + { + if (unlikely (!successful)) return false; + if (unlikely ((occupancy + occupancy / 2) >= mask && !alloc ())) return false; + + hash &= 0x3FFFFFFF; // We only store lower 30bit of hash + unsigned int tombstone = (unsigned int) -1; + unsigned int i = hash % prime; + unsigned length = 0; + unsigned step = 0; + while (items[i].is_used ()) + { + if ((std::is_integral::value || items[i].hash == hash) && + items[i] == key) + { + if (!overwrite) + return false; + else + break; + } + if (!items[i].is_real () && tombstone == (unsigned) -1) + tombstone = i; + i = (i + ++step) & mask; + length++; + } + + item_t &item = items[tombstone == (unsigned) -1 ? i : tombstone]; + + if (item.is_used ()) + { + occupancy--; + population -= item.is_real (); + } + + item.key = std::forward (key); + item.value = std::forward (value); + item.hash = hash; + item.set_used (true); + item.set_real (true); + + occupancy++; + population++; + + if (unlikely (length > max_chain_length) && occupancy * 8 > mask) + alloc (mask - 8); // This ensures we jump to next larger size + + return true; + } + + template + bool set (const K &key, VV&& value, bool overwrite = true) { return set_with_hash (key, hb_hash (key), std::forward (value), overwrite); } template - bool set (K key, VV&& value) { return set_with_hash (key, hb_hash (key), std::forward (value)); } + bool set (K &&key, VV&& value, bool overwrite = true) + { + uint32_t hash = hb_hash (key); + return set_with_hash (std::move (key), hash, std::forward (value), overwrite); + } + bool add (const K &key) + { + uint32_t hash = hb_hash (key); + return set_with_hash (key, hash, item_t::default_value ()); + } - const V& get (K key) const + const V& get_with_hash (const K &key, uint32_t hash) const { - if (unlikely (!items)) return item_t::default_value (); - unsigned int i = bucket_for (key); - return items[i].is_real () && items[i] == key ? items[i].value : item_t::default_value (); + if (!items) return item_t::default_value (); + auto *item = fetch_item (key, hash); + if (item) + return item->value; + return item_t::default_value (); + } + const V& get (const K &key) const + { + if (!items) return item_t::default_value (); + return get_with_hash (key, hb_hash (key)); } - void del (K key) { set_with_hash (key, hb_hash (key), item_t::default_value (), true); } + void del (const K &key) + { + if (!items) return; + auto *item = fetch_item (key, hb_hash (key)); + if (item) + { + item->set_real (false); + population--; + } + } /* Has interface. */ - typedef const V& value_t; - value_t operator [] (K k) const { return get (k); } + const V& operator [] (K k) const { return get (k); } template - bool has (K key, VV **vp = nullptr) const + bool has (const K &key, VV **vp = nullptr) const { - if (unlikely (!items)) - return false; - unsigned int i = bucket_for (key); - if (items[i].is_real () && items[i] == key) + if (!items) return false; + auto *item = fetch_item (key, hb_hash (key)); + if (item) { - if (vp) *vp = &items[i].value; + if (vp) *vp = std::addressof (item->value); return true; } - else - return false; + return false; + } + item_t *fetch_item (const K &key, uint32_t hash) const + { + hash &= 0x3FFFFFFF; // We only store lower 30bit of hash + unsigned int i = hash % prime; + unsigned step = 0; + while (items[i].is_used ()) + { + if ((std::is_integral::value || items[i].hash == hash) && + items[i] == key) + { + if (items[i].is_real ()) + return &items[i]; + else + return nullptr; + } + i = (i + ++step) & mask; + } + return nullptr; } /* Projection. */ - V operator () (K k) const { return get (k); } + const V& operator () (K k) const { return get (k); } + + unsigned size () const { return mask ? mask + 1 : 0; } void clear () { if (unlikely (!successful)) return; - if (items) - for (auto &_ : hb_iter (items, mask + 1)) - _.clear (); + for (auto &_ : hb_iter (items, size ())) + { + /* Reconstruct items. */ + _.~item_t (); + new (&_) item_t (); + } population = occupancy = 0; } @@ -246,11 +386,10 @@ struct hb_hashmap_t uint32_t hash () const { - uint32_t h = 0; - for (const auto &item : + hb_array (items, mask ? mask + 1 : 0) - | hb_filter (&item_t::is_real)) - h ^= item.total_hash (); - return h; + return + + iter_items () + | hb_reduce ([] (uint32_t h, const item_t &_) { return h ^ _.total_hash (); }, (uint32_t) 0u) + ; } bool is_equal (const hb_hashmap_t &other) const @@ -258,7 +397,7 @@ struct hb_hashmap_t if (population != other.population) return false; for (auto pair : iter ()) - if (get (pair.first) != pair.second) + if (other.get (pair.first) != pair.second) return false; return true; @@ -268,105 +407,86 @@ struct hb_hashmap_t unsigned int get_population () const { return population; } + void update (const hb_hashmap_t &other) + { + if (unlikely (!successful)) return; + + hb_copy (other, *this); + } + /* * Iterator */ - auto iter () const HB_AUTO_RETURN + + auto iter_items () const HB_AUTO_RETURN ( - + hb_array (items, mask ? mask + 1 : 0) + + hb_iter (items, this->size ()) | hb_filter (&item_t::is_real) - | hb_map (&item_t::get_pair) ) auto iter_ref () const HB_AUTO_RETURN ( - + hb_array (items, mask ? mask + 1 : 0) - | hb_filter (&item_t::is_real) + + this->iter_items () | hb_map (&item_t::get_pair_ref) ) - auto keys () const HB_AUTO_RETURN + auto iter () const HB_AUTO_RETURN ( - + hb_array (items, mask ? mask + 1 : 0) - | hb_filter (&item_t::is_real) - | hb_map (&item_t::key) - | hb_map (hb_ridentity) + + this->iter_items () + | hb_map (&item_t::get_pair) ) auto keys_ref () const HB_AUTO_RETURN ( - + hb_array (items, mask ? mask + 1 : 0) - | hb_filter (&item_t::is_real) - | hb_map (&item_t::key) + + this->iter_items () + | hb_map (&item_t::get_key) ) - auto values () const HB_AUTO_RETURN + auto keys () const HB_AUTO_RETURN ( - + hb_array (items, mask ? mask + 1 : 0) - | hb_filter (&item_t::is_real) - | hb_map (&item_t::value) + + this->keys_ref () | hb_map (hb_ridentity) ) auto values_ref () const HB_AUTO_RETURN ( - + hb_array (items, mask ? mask + 1 : 0) - | hb_filter (&item_t::is_real) - | hb_map (&item_t::value) + + this->iter_items () + | hb_map (&item_t::get_value) + ) + auto values () const HB_AUTO_RETURN + ( + + this->values_ref () + | hb_map (hb_ridentity) ) - /* Sink interface. */ - hb_hashmap_t& operator << (const hb_pair_t& v) - { set (v.first, v.second); return *this; } - - protected: - - template - bool set_with_hash (K key, uint32_t hash, VV&& value, bool is_delete=false) + /* C iterator. */ + bool next (int *idx, + K *key, + V *value) const { - if (unlikely (!successful)) return false; - if (unlikely ((occupancy + occupancy / 2) >= mask && !resize ())) return false; - unsigned int i = bucket_for_hash (key, hash); + unsigned i = (unsigned) (*idx + 1); - if (is_delete && items[i].key != key) - return true; /* Trying to delete non-existent key. */ + unsigned count = size (); + while (i < count && !items[i].is_real ()) + i++; - if (items[i].is_used ()) + if (i >= count) { - occupancy--; - if (!items[i].is_tombstone ()) - population--; + *idx = -1; + return false; } - items[i].key = key; - items[i].value = std::forward (value); - items[i].hash = hash; - items[i].set_used (true); - items[i].set_tombstone (is_delete); - - occupancy++; - if (!is_delete) - population++; + *key = items[i].key; + *value = items[i].value; + *idx = (signed) i; return true; } - unsigned int bucket_for (const K &key) const - { - return bucket_for_hash (key, hb_hash (key)); - } - - unsigned int bucket_for_hash (const K &key, uint32_t hash) const - { - hash &= 0x3FFFFFFF; // We only store lower 30bit of hash - unsigned int i = hash % prime; - unsigned int step = 0; - unsigned int tombstone = (unsigned) -1; - while (items[i].is_used ()) - { - if (items[i].hash == hash && items[i] == key) - return i; - if (tombstone == (unsigned) -1 && items[i].is_tombstone ()) - tombstone = i; - i = (i + ++step) & mask; - } - return tombstone == (unsigned) -1 ? i : tombstone; - } + /* Sink interface. */ + hb_hashmap_t& operator << (const hb_pair_t& v) + { set (v.first, v.second); return *this; } + hb_hashmap_t& operator << (const hb_pair_t& v) + { set (v.first, std::move (v.second)); return *this; } + hb_hashmap_t& operator << (const hb_pair_t& v) + { set (std::move (v.first), v.second); return *this; } + hb_hashmap_t& operator << (const hb_pair_t& v) + { set (std::move (v.first), std::move (v.second)); return *this; } static unsigned int prime_for (unsigned int shift) { @@ -435,46 +555,14 @@ struct hb_map_t : hb_hashmap_t> lst) : hashmap (lst) {} + hb_map_t (std::initializer_list lst) : hashmap (lst) {} template hb_map_t (const Iterable &o) : hashmap (o) {} }; -template -static inline -hb_hashmap_t* hb_hashmap_create () -{ - using hashmap = hb_hashmap_t; - hashmap* map; - if (!(map = hb_object_create ())) - return nullptr; - - return map; -} - -template -static inline -void hb_hashmap_destroy (hb_hashmap_t* map) -{ - if (!hb_object_destroy (map)) - return; - - hb_free (map); -} - -namespace hb { - -template -struct vtable> -{ - static constexpr auto destroy = hb_hashmap_destroy; -}; - -} - #endif /* HB_MAP_HH */ diff --git a/libs/harfbuzz/src/hb-meta.hh b/libs/harfbuzz/src/hb-meta.hh index 52a6791e3..52ff4a841 100644 --- a/libs/harfbuzz/src/hb-meta.hh +++ b/libs/harfbuzz/src/hb-meta.hh @@ -112,8 +112,7 @@ template auto _hb_try_add_pointer (hb_priority<1>) -> hb_type_ident template using hb_add_pointer = decltype (_hb_try_add_pointer (hb_prioritize)); -/* TODO Add feature-parity to std::decay. */ -template using hb_decay = hb_remove_const>; +template using hb_decay = typename std::decay::type; #define hb_is_convertible(From,To) std::is_convertible::value @@ -154,8 +153,8 @@ struct hb_reference_wrapper hb_reference_wrapper (T v) : v (v) {} bool operator == (const hb_reference_wrapper& o) const { return v == o.v; } bool operator != (const hb_reference_wrapper& o) const { return v != o.v; } - operator T () const { return v; } - T get () const { return v; } + operator T& () { return v; } + T& get () { return v; } T v; }; template @@ -164,8 +163,8 @@ struct hb_reference_wrapper hb_reference_wrapper (T& v) : v (std::addressof (v)) {} bool operator == (const hb_reference_wrapper& o) const { return v == o.v; } bool operator != (const hb_reference_wrapper& o) const { return v != o.v; } - operator T& () const { return *v; } - T& get () const { return *v; } + operator T& () { return *v; } + T& get () { return *v; } T* v; }; diff --git a/libs/harfbuzz/src/hb-ms-feature-ranges.hh b/libs/harfbuzz/src/hb-ms-feature-ranges.hh index d40fdeaa8..23a5c6f8b 100644 --- a/libs/harfbuzz/src/hb-ms-feature-ranges.hh +++ b/libs/harfbuzz/src/hb-ms-feature-ranges.hh @@ -30,6 +30,9 @@ #include "hb.hh" +/* Variations of this code exist in hb-coretext-shape.cc as well + * as hb-aat-map.cc... */ + typedef struct hb_ms_feature_t { uint32_t tag_le; uint32_t value; @@ -166,7 +169,7 @@ hb_ms_setup_features (const hb_feature_t *features, { auto *feature = active_features.lsearch (event->feature); if (feature) - active_features.remove (feature - active_features.arrayZ); + active_features.remove_ordered (feature - active_features.arrayZ); } } diff --git a/libs/harfbuzz/src/hb-multimap.hh b/libs/harfbuzz/src/hb-multimap.hh new file mode 100644 index 000000000..0184279c1 --- /dev/null +++ b/libs/harfbuzz/src/hb-multimap.hh @@ -0,0 +1,96 @@ +/* + * Copyright © 2022 Behdad Esfahbod + * + * 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. + */ + +#ifndef HB_MULTIMAP_HH +#define HB_MULTIMAP_HH + +#include "hb.hh" +#include "hb-map.hh" +#include "hb-vector.hh" + + +/* + * hb_multimap_t + */ + +struct hb_multimap_t +{ + void add (hb_codepoint_t k, hb_codepoint_t v) + { + hb_vector_t *m; + if (multiples.has (k, &m)) + { + m->push (v); + return; + } + + hb_codepoint_t *old_v; + if (singulars.has (k, &old_v)) + { + hb_codepoint_t old = *old_v; + singulars.del (k); + + multiples.set (k, hb_vector_t {old, v}); + return; + } + + singulars.set (k, v); + } + + hb_array_t get (hb_codepoint_t k) const + { + const hb_codepoint_t *v; + if (singulars.has (k, &v)) + return hb_array (v, 1); + + hb_vector_t *m; + if (multiples.has (k, &m)) + return m->as_array (); + + return hb_array_t (); + } + + bool in_error () const + { + if (singulars.in_error () || multiples.in_error ()) + return true; + for (const auto &m : multiples.values_ref ()) + if (m.in_error ()) + return true; + return false; + } + + void alloc (unsigned size) + { + singulars.alloc (size); + } + + protected: + hb_map_t singulars; + hb_hashmap_t> multiples; +}; + + + +#endif /* HB_MULTIMAP_HH */ diff --git a/libs/harfbuzz/src/hb-mutex.hh b/libs/harfbuzz/src/hb-mutex.hh index 6914b2245..e329d9864 100644 --- a/libs/harfbuzz/src/hb-mutex.hh +++ b/libs/harfbuzz/src/hb-mutex.hh @@ -60,7 +60,7 @@ typedef pthread_mutex_t hb_mutex_impl_t; #elif !defined(HB_NO_MT) && !defined(HB_MUTEX_IMPL_STD_MUTEX) && defined(_WIN32) typedef CRITICAL_SECTION hb_mutex_impl_t; -#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) #define hb_mutex_impl_init(M) InitializeCriticalSectionEx (M, 0, 0) #else #define hb_mutex_impl_init(M) InitializeCriticalSection (M) @@ -97,6 +97,9 @@ struct hb_mutex_t /* Create space for, but do not initialize m. */ alignas(hb_mutex_impl_t) char m[sizeof (hb_mutex_impl_t)]; + hb_mutex_t () { init (); } + ~hb_mutex_t () { fini (); } + #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-align" void init () { hb_mutex_impl_init ((hb_mutex_impl_t *) m); } @@ -108,10 +111,11 @@ struct hb_mutex_t struct hb_lock_t { - hb_lock_t (hb_mutex_t &mutex_) : mutex (mutex_) { mutex.lock (); } - ~hb_lock_t () { mutex.unlock (); } + hb_lock_t (hb_mutex_t &mutex_) : mutex (&mutex_) { mutex->lock (); } + hb_lock_t (hb_mutex_t *mutex_) : mutex (mutex_) { if (mutex) mutex->lock (); } + ~hb_lock_t () { if (mutex) mutex->unlock (); } private: - hb_mutex_t &mutex; + hb_mutex_t *mutex; }; diff --git a/libs/harfbuzz/src/hb-null.hh b/libs/harfbuzz/src/hb-null.hh index 0d7f4da79..854485d3d 100644 --- a/libs/harfbuzz/src/hb-null.hh +++ b/libs/harfbuzz/src/hb-null.hh @@ -37,7 +37,7 @@ /* Global nul-content Null pool. Enlarge as necessary. */ -#define HB_NULL_POOL_SIZE 448 +#define HB_NULL_POOL_SIZE 640 template struct _hb_has_min_size : hb_false_type {}; @@ -85,7 +85,7 @@ using hb_null_size = _hb_null_size; template struct _hb_static_size : hb_integral_constant {}; template -struct _hb_static_size> : hb_integral_constant {}; +struct _hb_static_size> : hb_integral_constant {}; template using hb_static_size = _hb_static_size; #define hb_static_size(T) hb_static_size::value @@ -176,7 +176,7 @@ template static inline Type& Crap () { static_assert (hb_null_size (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE."); Type *obj = reinterpret_cast (_hb_CrapPool); - memcpy (obj, &Null (Type), sizeof (*obj)); + memcpy (obj, std::addressof (Null (Type)), sizeof (*obj)); return *obj; } template @@ -211,11 +211,11 @@ struct hb_nonnull_ptr_t T * operator = (T *v_) { return v = v_; } T * operator -> () const { return get (); } T & operator * () const { return *get (); } - T ** operator & () const { return &v; } + T ** operator & () const { return std::addressof (v); } /* Only auto-cast to const types. */ template operator const C * () const { return get (); } operator const char * () const { return (const char *) get (); } - T * get () const { return v ? v : const_cast (&Null (T)); } + T * get () const { return v ? v : const_cast (std::addressof (Null (T))); } T * get_raw () const { return v; } private: diff --git a/libs/harfbuzz/src/hb-number.cc b/libs/harfbuzz/src/hb-number.cc index 6e4f3f7eb..c52b284e1 100644 --- a/libs/harfbuzz/src/hb-number.cc +++ b/libs/harfbuzz/src/hb-number.cc @@ -24,7 +24,6 @@ */ #include "hb.hh" -#include "hb-machinery.hh" #include "hb-number.hh" #include "hb-number-parser.hh" diff --git a/libs/harfbuzz/src/hb-object.hh b/libs/harfbuzz/src/hb-object.hh index 9876c2923..5cffe1666 100644 --- a/libs/harfbuzz/src/hb-object.hh +++ b/libs/harfbuzz/src/hb-object.hh @@ -69,7 +69,7 @@ struct hb_lockable_set_t item = items.push (v); l.unlock (); } - return item; + return items.in_error () ? nullptr : item; } template @@ -80,7 +80,7 @@ struct hb_lockable_set_t if (item) { item_t old = *item; - *item = items[items.length - 1]; + *item = std::move (items.tail ()); items.pop (); l.unlock (); old.fini (); @@ -123,7 +123,7 @@ struct hb_lockable_set_t l.lock (); while (items.length) { - item_t old = items[items.length - 1]; + item_t old = items.tail (); items.pop (); l.unlock (); old.fini (); @@ -175,14 +175,34 @@ struct hb_user_data_array_t void init () { lock.init (); items.init (); } - HB_INTERNAL bool set (hb_user_data_key_t *key, - void * data, - hb_destroy_func_t destroy, - hb_bool_t replace); + void fini () { items.fini (lock); lock.fini (); } - HB_INTERNAL void *get (hb_user_data_key_t *key); + bool set (hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace) + { + if (!key) + return false; - void fini () { items.fini (lock); lock.fini (); } + if (replace) { + if (!data && !destroy) { + items.remove (key, lock); + return true; + } + } + hb_user_data_item_t item = {key, data, destroy}; + bool ret = !!items.replace_or_insert (item, lock, (bool) replace); + + return ret; + } + + void *get (hb_user_data_key_t *key) + { + hb_user_data_item_t item = {nullptr, nullptr, nullptr}; + + return items.find (key, &item, lock) ? item.data : nullptr; + } }; @@ -305,7 +325,7 @@ retry: hb_user_data_array_t *user_data = obj->header.user_data.get_acquire (); if (unlikely (!user_data)) { - user_data = (hb_user_data_array_t *) hb_calloc (sizeof (hb_user_data_array_t), 1); + user_data = (hb_user_data_array_t *) hb_calloc (1, sizeof (hb_user_data_array_t)); if (unlikely (!user_data)) return false; user_data->init (); diff --git a/libs/harfbuzz/src/hb-open-file.hh b/libs/harfbuzz/src/hb-open-file.hh index 6eee5827c..6c98226f2 100644 --- a/libs/harfbuzz/src/hb-open-file.hh +++ b/libs/harfbuzz/src/hb-open-file.hh @@ -90,7 +90,7 @@ typedef struct OpenTypeOffsetTable { if (table_count) { - + tables.sub_array (start_offset, table_count) + + tables.as_array ().sub_array (start_offset, table_count) | hb_map (&TableRecord::tag) | hb_sink (hb_array (table_tags, *table_count)) ; @@ -131,7 +131,7 @@ typedef struct OpenTypeOffsetTable sfnt_version = sfnt_tag; /* Take space for numTables, searchRange, entrySelector, RangeShift * and the TableRecords themselves. */ - unsigned num_items = it.len (); + unsigned num_items = hb_len (it); if (unlikely (!tables.serialize (c, num_items))) return_trace (false); const char *dir_end = (const char *) c->head; @@ -145,7 +145,7 @@ typedef struct OpenTypeOffsetTable unsigned len = blob->length; /* Allocate room for the table and copy it. */ - char *start = (char *) c->allocate_size (len); + char *start = (char *) c->allocate_size (len, false); if (unlikely (!start)) return false; TableRecord &rec = tables.arrayZ[i]; @@ -158,7 +158,7 @@ typedef struct OpenTypeOffsetTable return_trace (false); if (likely (len)) - memcpy (start, blob->data, len); + hb_memcpy (start, blob->data, len); /* 4-byte alignment. */ c->align (4); @@ -250,7 +250,7 @@ struct TTCHeader { switch (u.header.version.major) { case 2: /* version 2 is compatible with version 1 */ - case 1: return u.version1.get_face_count (); + case 1: hb_barrier (); return u.version1.get_face_count (); default:return 0; } } @@ -258,7 +258,7 @@ struct TTCHeader { switch (u.header.version.major) { case 2: /* version 2 is compatible with version 1 */ - case 1: return u.version1.get_face (i); + case 1: hb_barrier (); return u.version1.get_face (i); default:return Null (OpenTypeFontFace); } } @@ -267,9 +267,10 @@ struct TTCHeader { TRACE_SANITIZE (this); if (unlikely (!u.header.version.sanitize (c))) return_trace (false); + hb_barrier (); switch (u.header.version.major) { case 2: /* version 2 is compatible with version 1 */ - case 1: return_trace (u.version1.sanitize (c)); + case 1: hb_barrier (); return_trace (u.version1.sanitize (c)); default:return_trace (true); } } @@ -302,6 +303,7 @@ struct ResourceRecord TRACE_SANITIZE (this); return_trace (c->check_struct (this) && offset.sanitize (c, data_base) && + hb_barrier () && get_face (data_base).sanitize (c)); } @@ -337,6 +339,7 @@ struct ResourceTypeRecord { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && + hb_barrier () && resourcesZ.sanitize (c, type_base, get_resource_count (), data_base)); @@ -385,6 +388,7 @@ struct ResourceMap { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && + hb_barrier () && typeList.sanitize (c, this, &(this+typeList), data_base)); @@ -428,6 +432,7 @@ struct ResourceForkHeader { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && + hb_barrier () && data.sanitize (c, this, dataLen) && map.sanitize (c, this, &(this+data))); } @@ -508,6 +513,7 @@ struct OpenTypeFontFile { TRACE_SANITIZE (this); if (unlikely (!u.tag.sanitize (c))) return_trace (false); + hb_barrier (); switch (u.tag) { case CFFTag: /* All the non-collection tags */ case TrueTag: diff --git a/libs/harfbuzz/src/hb-open-type.hh b/libs/harfbuzz/src/hb-open-type.hh index e66f45182..6655259b7 100644 --- a/libs/harfbuzz/src/hb-open-type.hh +++ b/libs/harfbuzz/src/hb-open-type.hh @@ -132,6 +132,89 @@ struct HBUINT15 : HBUINT16 DEFINE_SIZE_STATIC (2); }; +/* 32-bit unsigned integer with variable encoding. */ +struct HBUINT32VAR +{ + unsigned get_size () const + { + unsigned b0 = v[0]; + if (b0 < 0x80) + return 1; + else if (b0 < 0xC0) + return 2; + else if (b0 < 0xE0) + return 3; + else if (b0 < 0xF0) + return 4; + else + return 5; + } + + static unsigned get_size (uint32_t v) + { + if (v < 0x80) + return 1; + else if (v < 0x4000) + return 2; + else if (v < 0x200000) + return 3; + else if (v < 0x10000000) + return 4; + else + return 5; + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_range (v, 1) && + hb_barrier () && + c->check_range (v, get_size ())); + } + + operator uint32_t () const + { + unsigned b0 = v[0]; + if (b0 < 0x80) + return b0; + else if (b0 < 0xC0) + return ((b0 & 0x3F) << 8) | v[1]; + else if (b0 < 0xE0) + return ((b0 & 0x1F) << 16) | (v[1] << 8) | v[2]; + else if (b0 < 0xF0) + return ((b0 & 0x0F) << 24) | (v[1] << 16) | (v[2] << 8) | v[3]; + else + return (v[1] << 24) | (v[2] << 16) | (v[3] << 8) | v[4]; + } + + static bool serialize (hb_serialize_context_t *c, uint32_t v) + { + unsigned len = get_size (v); + + unsigned char *buf = c->allocate_size (len, false); + if (unlikely (!buf)) + return false; + + unsigned char *p = buf + len; + for (unsigned i = 0; i < len; i++) + { + *--p = v & 0xFF; + v >>= 8; + } + + if (len > 1) + buf[0] |= ((1 << (len - 1)) - 1) << (9 - len); + + return true; + } + + protected: + unsigned char v[5]; + + public: + DEFINE_SIZE_MIN (1); +}; + /* 16-bit signed integer (HBINT16) that describes a quantity in FUnits. */ typedef HBINT16 FWORD; @@ -147,8 +230,12 @@ struct HBFixed : Type static constexpr float shift = (float) (1 << fraction_bits); static_assert (Type::static_size * 8 > fraction_bits, ""); - HBFixed& operator = (typename Type::type i ) { Type::operator= (i); return *this; } - float to_float () const { return ((int32_t) Type::v) / shift; } + operator signed () const = delete; + operator unsigned () const = delete; + explicit operator float () const { return to_float (); } + typename Type::type to_int () const { return Type::v; } + void set_int (typename Type::type i ) { Type::v = i; } + float to_float (float offset = 0) const { return ((int32_t) Type::v + offset) / shift; } void set_float (float f) { Type::v = roundf (f * shift); } public: DEFINE_SIZE_STATIC (Type::static_size); @@ -156,6 +243,8 @@ struct HBFixed : Type /* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */ using F2DOT14 = HBFixed; +using F4DOT12 = HBFixed; +using F6DOT10 = HBFixed; /* 32-bit signed fixed-point number (16.16). */ using F16DOT16 = HBFixed; @@ -209,6 +298,12 @@ typedef Index NameID; struct VarIdx : HBUINT32 { static constexpr unsigned NO_VARIATION = 0xFFFFFFFFu; + static_assert (NO_VARIATION == HB_OT_LAYOUT_NO_VARIATIONS_INDEX, ""); + static uint32_t add (uint32_t i, unsigned short v) + { + if (i == NO_VARIATION) return i; + return i + v; + } VarIdx& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; } }; DECLARE_NULL_NAMESPACE_BYTES (OT, VarIdx); @@ -298,9 +393,11 @@ struct _hb_has_null static Type *get_crap () { return &Crap (Type); } }; -template +template struct OffsetTo : Offset { + using target_t = Type; + // Make sure Type is not unbounded; works only for types that are fully defined at OffsetTo time. static_assert (has_null == false || (hb_has_null_size (Type) || !hb_has_min_size (Type)), ""); @@ -322,22 +419,22 @@ struct OffsetTo : Offset } template + hb_enable_if (hb_is_convertible (const Base, const BaseType *))> friend const Type& operator + (const Base &base, const OffsetTo &offset) { return offset ((const void *) base); } template + hb_enable_if (hb_is_convertible (const Base, const BaseType *))> friend const Type& operator + (const OffsetTo &offset, const Base &base) { return offset ((const void *) base); } template + hb_enable_if (hb_is_convertible (Base, BaseType *))> friend Type& operator + (Base &&base, OffsetTo &offset) { return offset ((void *) base); } template + hb_enable_if (hb_is_convertible (Base, BaseType *))> friend Type& operator + (OffsetTo &offset, Base &&base) { return offset ((void *) base); } - template + template bool serialize_subset (hb_subset_context_t *c, const OffsetTo& src, - const void *src_base, Ts&&... ds) + const Base *src_base, Ts&&... ds) { *this = 0; if (src.is_null ()) @@ -401,20 +498,25 @@ struct OffsetTo : Offset const void *src_base, unsigned dst_bias = 0) { return serialize_copy (c, src, src_base, dst_bias, hb_serialize_context_t::Head); } - bool sanitize_shallow (hb_sanitize_context_t *c, const void *base) const + bool sanitize_shallow (hb_sanitize_context_t *c, const BaseType *base) const { TRACE_SANITIZE (this); if (unlikely (!c->check_struct (this))) return_trace (false); - if (unlikely (this->is_null ())) return_trace (true); + hb_barrier (); + //if (unlikely (this->is_null ())) return_trace (true); if (unlikely ((const char *) base + (unsigned) *this < (const char *) base)) return_trace (false); return_trace (true); } template - bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif + bool sanitize (hb_sanitize_context_t *c, const BaseType *base, Ts&&... ds) const { TRACE_SANITIZE (this); return_trace (sanitize_shallow (c, base) && + hb_barrier () && (this->is_null () || c->dispatch (StructAtOffset (base, *this), std::forward (ds)...) || neuter (c))); @@ -429,14 +531,14 @@ struct OffsetTo : Offset DEFINE_SIZE_STATIC (sizeof (OffsetType)); }; /* Partial specializations. */ -template using Offset16To = OffsetTo; -template using Offset24To = OffsetTo; -template using Offset32To = OffsetTo; +template using Offset16To = OffsetTo; +template using Offset24To = OffsetTo; +template using Offset32To = OffsetTo; -template using NNOffsetTo = OffsetTo; -template using NNOffset16To = Offset16To; -template using NNOffset24To = Offset24To; -template using NNOffset32To = Offset32To; +template using NNOffsetTo = OffsetTo; +template using NNOffset16To = Offset16To; +template using NNOffset24To = Offset24To; +template using NNOffset32To = Offset32To; /* @@ -451,24 +553,16 @@ struct UnsizedArrayOf HB_DELETE_CREATE_COPY_ASSIGN (UnsizedArrayOf); - const Type& operator [] (int i_) const + const Type& operator [] (unsigned int i) const { - unsigned int i = (unsigned int) i_; - const Type *p = &arrayZ[i]; - if (unlikely ((const void *) p < (const void *) arrayZ)) return Null (Type); /* Overflowed. */ - _hb_compiler_memory_r_barrier (); - return *p; + return arrayZ[i]; } - Type& operator [] (int i_) + Type& operator [] (unsigned int i) { - unsigned int i = (unsigned int) i_; - Type *p = &arrayZ[i]; - if (unlikely ((const void *) p < (const void *) arrayZ)) return Crap (Type); /* Overflowed. */ - _hb_compiler_memory_r_barrier (); - return *p; + return arrayZ[i]; } - unsigned int get_size (unsigned int len) const + static unsigned int get_size (unsigned int len) { return len * Type::static_size; } template operator T * () { return arrayZ; } @@ -493,10 +587,10 @@ struct UnsizedArrayOf void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1) { as_array (len).qsort (start, end); } - bool serialize (hb_serialize_context_t *c, unsigned int items_len) + bool serialize (hb_serialize_context_t *c, unsigned int items_len, bool clear = true) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend (this, items_len))) return_trace (false); + if (unlikely (!c->extend_size (this, get_size (items_len), clear))) return_trace (false); return_trace (true); } template + HB_ALWAYS_INLINE bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c, count))) return_trace (false); if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); + hb_barrier (); for (unsigned int i = 0; i < count; i++) if (unlikely (!c->dispatch (arrayZ[i], std::forward (ds)...))) return_trace (false); @@ -546,27 +642,27 @@ struct UnsizedArrayOf }; /* Unsized array of offset's */ -template -using UnsizedArray16OfOffsetTo = UnsizedArrayOf>; +template +using UnsizedArray16OfOffsetTo = UnsizedArrayOf>; /* Unsized array of offsets relative to the beginning of the array itself. */ -template -struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo +template +struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo { const Type& operator [] (int i_) const { unsigned int i = (unsigned int) i_; - const OffsetTo *p = &this->arrayZ[i]; + const OffsetTo *p = &this->arrayZ[i]; if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Null (Type); /* Overflowed. */ - _hb_compiler_memory_r_barrier (); + hb_barrier (); return this+*p; } Type& operator [] (int i_) { unsigned int i = (unsigned int) i_; - const OffsetTo *p = &this->arrayZ[i]; + const OffsetTo *p = &this->arrayZ[i]; if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Crap (Type); /* Overflowed. */ - _hb_compiler_memory_r_barrier (); + hb_barrier (); return this+*p; } @@ -574,7 +670,7 @@ struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo + return_trace ((UnsizedArray16OfOffsetTo ::sanitize (c, count, this, std::forward (ds)...))); } }; @@ -617,14 +713,14 @@ struct ArrayOf { unsigned int i = (unsigned int) i_; if (unlikely (i >= len)) return Null (Type); - _hb_compiler_memory_r_barrier (); + hb_barrier (); return arrayZ[i]; } Type& operator [] (int i_) { unsigned int i = (unsigned int) i_; if (unlikely (i >= len)) return Crap (Type); - _hb_compiler_memory_r_barrier (); + hb_barrier (); return arrayZ[i]; } @@ -646,14 +742,9 @@ struct ArrayOf operator iter_t () const { return iter (); } operator writer_t () { return writer (); } - hb_array_t sub_array (unsigned int start_offset, unsigned int count) const - { return as_array ().sub_array (start_offset, count); } - hb_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const - { return as_array ().sub_array (start_offset, count); } - hb_array_t sub_array (unsigned int start_offset, unsigned int count) - { return as_array ().sub_array (start_offset, count); } - hb_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) - { return as_array ().sub_array (start_offset, count); } + /* Faster range-based for loop. */ + const Type *begin () const { return arrayZ; } + const Type *end () const { return arrayZ + len; } template Type &lsearch (const T &x, Type ¬_found = Crap (Type)) @@ -667,15 +758,15 @@ struct ArrayOf unsigned int to_store = (unsigned int) -1) const { return as_array ().lfind (x, i, not_found, to_store); } - void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1) - { as_array ().qsort (start, end); } + void qsort () + { as_array ().qsort (); } - HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned items_len) + HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned items_len, bool clear = true) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (this))) return_trace (false); c->check_assign (len, items_len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW); - if (unlikely (!c->extend (this))) return_trace (false); + if (unlikely (!c->extend_size (this, get_size (), clear))) return_trace (false); return_trace (true); } template + HB_ALWAYS_INLINE bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return_trace (false); if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); + hb_barrier (); unsigned int count = len; for (unsigned int i = 0; i < count; i++) if (unlikely (!c->dispatch (arrayZ[i], std::forward (ds)...))) @@ -730,7 +823,9 @@ struct ArrayOf bool sanitize_shallow (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (len.sanitize (c) && c->check_array (arrayZ, len)); + return_trace (len.sanitize (c) && + hb_barrier () && + c->check_array_sized (arrayZ, len, sizeof (LenType))); } public: @@ -745,6 +840,7 @@ template using Array32Of = ArrayOf; using PString = ArrayOf; /* Array of Offset's */ +template using Array8OfOffset24To = ArrayOf, HBUINT8>; template using Array16OfOffset16To = ArrayOf, HBUINT16>; template using Array16OfOffset32To = ArrayOf, HBUINT16>; template using Array32OfOffset32To = ArrayOf, HBUINT32>; @@ -757,14 +853,14 @@ struct List16OfOffsetTo : ArrayOf, HBUINT16> { unsigned int i = (unsigned int) i_; if (unlikely (i >= this->len)) return Null (Type); - _hb_compiler_memory_r_barrier (); + hb_barrier (); return this+this->arrayZ[i]; } const Type& operator [] (int i_) { unsigned int i = (unsigned int) i_; if (unlikely (i >= this->len)) return Crap (Type); - _hb_compiler_memory_r_barrier (); + hb_barrier (); return this+this->arrayZ[i]; } @@ -791,7 +887,7 @@ template using List16OfOffset16To = List16OfOffsetTo; /* An array starting at second element. */ -template +template struct HeadlessArrayOf { static constexpr unsigned item_size = Type::static_size; @@ -802,14 +898,14 @@ struct HeadlessArrayOf { unsigned int i = (unsigned int) i_; if (unlikely (i >= lenP1 || !i)) return Null (Type); - _hb_compiler_memory_r_barrier (); + hb_barrier (); return arrayZ[i-1]; } Type& operator [] (int i_) { unsigned int i = (unsigned int) i_; if (unlikely (i >= lenP1 || !i)) return Crap (Type); - _hb_compiler_memory_r_barrier (); + hb_barrier (); return arrayZ[i-1]; } unsigned int get_size () const @@ -828,21 +924,25 @@ struct HeadlessArrayOf operator iter_t () const { return iter (); } operator writer_t () { return writer (); } - bool serialize (hb_serialize_context_t *c, unsigned int items_len) + /* Faster range-based for loop. */ + const Type *begin () const { return arrayZ; } + const Type *end () const { return arrayZ + get_length (); } + + HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned int items_len, bool clear = true) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (this))) return_trace (false); c->check_assign (lenP1, items_len + 1, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW); - if (unlikely (!c->extend (this))) return_trace (false); + if (unlikely (!c->extend_size (this, get_size (), clear))) return_trace (false); return_trace (true); } template - bool serialize (hb_serialize_context_t *c, Iterator items) + HB_NODISCARD bool serialize (hb_serialize_context_t *c, Iterator items) { TRACE_SERIALIZE (this); - unsigned count = items.len (); - if (unlikely (!serialize (c, count))) return_trace (false); + unsigned count = hb_len (items); + if (unlikely (!serialize (c, count, false))) return_trace (false); /* TODO Umm. Just exhaust the iterator instead? Being extra * cautious right now.. */ for (unsigned i = 0; i < count; i++, ++items) @@ -851,11 +951,13 @@ struct HeadlessArrayOf } template + HB_ALWAYS_INLINE bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return_trace (false); if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); + hb_barrier (); unsigned int count = get_length (); for (unsigned int i = 0; i < count; i++) if (unlikely (!c->dispatch (arrayZ[i], std::forward (ds)...))) @@ -868,7 +970,8 @@ struct HeadlessArrayOf { TRACE_SANITIZE (this); return_trace (lenP1.sanitize (c) && - (!lenP1 || c->check_array (arrayZ, lenP1 - 1))); + hb_barrier () && + (!lenP1 || c->check_array_sized (arrayZ, lenP1 - 1, sizeof (LenType)))); } public: @@ -877,6 +980,7 @@ struct HeadlessArrayOf public: DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); }; +template using HeadlessArray16Of = HeadlessArrayOf; /* An array storing length-1. */ template @@ -888,25 +992,27 @@ struct ArrayOfM1 { unsigned int i = (unsigned int) i_; if (unlikely (i > lenM1)) return Null (Type); - _hb_compiler_memory_r_barrier (); + hb_barrier (); return arrayZ[i]; } Type& operator [] (int i_) { unsigned int i = (unsigned int) i_; if (unlikely (i > lenM1)) return Crap (Type); - _hb_compiler_memory_r_barrier (); + hb_barrier (); return arrayZ[i]; } unsigned int get_size () const { return lenM1.static_size + (lenM1 + 1) * Type::static_size; } template + HB_ALWAYS_INLINE bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return_trace (false); if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); + hb_barrier (); unsigned int count = lenM1 + 1; for (unsigned int i = 0; i < count; i++) if (unlikely (!c->dispatch (arrayZ[i], std::forward (ds)...))) @@ -919,7 +1025,8 @@ struct ArrayOfM1 { TRACE_SANITIZE (this); return_trace (lenM1.sanitize (c) && - (c->check_array (arrayZ, lenM1 + 1))); + hb_barrier () && + (c->check_array_sized (arrayZ, lenM1 + 1, sizeof (LenType)))); } public: @@ -944,14 +1051,9 @@ struct SortedArrayOf : ArrayOf operator iter_t () const { return iter (); } operator writer_t () { return writer (); } - hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int count) const - { return as_array ().sub_array (start_offset, count); } - hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const - { return as_array ().sub_array (start_offset, count); } - hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int count) - { return as_array ().sub_array (start_offset, count); } - hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) - { return as_array ().sub_array (start_offset, count); } + /* Faster range-based for loop. */ + const Type *begin () const { return this->arrayZ; } + const Type *end () const { return this->arrayZ + this->len; } bool serialize (hb_serialize_context_t *c, unsigned int items_len) { @@ -968,6 +1070,13 @@ struct SortedArrayOf : ArrayOf return_trace (ret); } + SortedArrayOf* copy (hb_serialize_context_t *c) const + { + TRACE_SERIALIZE (this); + SortedArrayOf* out = reinterpret_cast (ArrayOf::copy (c)); + return_trace (out); + } + template Type &bsearch (const T &x, Type ¬_found = Crap (Type)) { return *as_array ().bsearch (x, ¬_found); } @@ -1075,14 +1184,14 @@ struct VarSizedBinSearchArrayOf { unsigned int i = (unsigned int) i_; if (unlikely (i >= get_length ())) return Null (Type); - _hb_compiler_memory_r_barrier (); + hb_barrier (); return StructAtOffset (&bytesZ, i * header.unitSize); } Type& operator [] (int i_) { unsigned int i = (unsigned int) i_; if (unlikely (i >= get_length ())) return Crap (Type); - _hb_compiler_memory_r_barrier (); + hb_barrier (); return StructAtOffset (&bytesZ, i * header.unitSize); } unsigned int get_length () const @@ -1091,11 +1200,13 @@ struct VarSizedBinSearchArrayOf { return header.static_size + header.nUnits * header.unitSize; } template + HB_ALWAYS_INLINE bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return_trace (false); if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); + hb_barrier (); unsigned int count = get_length (); for (unsigned int i = 0; i < count; i++) if (unlikely (!(*this)[i].sanitize (c, std::forward (ds)...))) @@ -1122,6 +1233,7 @@ struct VarSizedBinSearchArrayOf { TRACE_SANITIZE (this); return_trace (header.sanitize (c) && + hb_barrier () && Type::static_size <= header.unitSize && c->check_range (bytesZ.arrayZ, header.nUnits, @@ -1136,6 +1248,638 @@ struct VarSizedBinSearchArrayOf }; +/* CFF INDEX */ + +template +struct CFFIndex +{ + unsigned int offset_array_size () const + { return offSize * (count + 1); } + + template + bool serialize (hb_serialize_context_t *c, + const Iterable &iterable, + const unsigned *p_data_size = nullptr, + unsigned min_off_size = 0) + { + TRACE_SERIALIZE (this); + unsigned data_size; + if (p_data_size) + data_size = *p_data_size; + else + total_size (iterable, &data_size); + + auto it = hb_iter (iterable); + if (unlikely (!serialize_header (c, +it, data_size, min_off_size))) return_trace (false); + unsigned char *ret = c->allocate_size (data_size, false); + if (unlikely (!ret)) return_trace (false); + for (const auto &_ : +it) + { + unsigned len = _.length; + if (!len) + continue; + if (len <= 1) + { + *ret++ = *_.arrayZ; + continue; + } + hb_memcpy (ret, _.arrayZ, len); + ret += len; + } + return_trace (true); + } + + template + bool serialize_header (hb_serialize_context_t *c, + Iterator it, + unsigned data_size, + unsigned min_off_size = 0) + { + TRACE_SERIALIZE (this); + + unsigned off_size = (hb_bit_storage (data_size + 1) + 7) / 8; + off_size = hb_max(min_off_size, off_size); + + /* serialize CFFIndex header */ + if (unlikely (!c->extend_min (this))) return_trace (false); + this->count = hb_len (it); + if (!this->count) return_trace (true); + if (unlikely (!c->extend (this->offSize))) return_trace (false); + this->offSize = off_size; + if (unlikely (!c->allocate_size (off_size * (this->count + 1), false))) + return_trace (false); + + /* serialize indices */ + unsigned int offset = 1; + if (HB_OPTIMIZE_SIZE_VAL) + { + unsigned int i = 0; + for (const auto &_ : +it) + { + set_offset_at (i++, offset); + offset += hb_len_of (_); + } + set_offset_at (i, offset); + } + else + switch (off_size) + { + case 1: + { + HBUINT8 *p = (HBUINT8 *) offsets; + for (const auto &_ : +it) + { + *p++ = offset; + offset += hb_len_of (_); + } + *p = offset; + } + break; + case 2: + { + HBUINT16 *p = (HBUINT16 *) offsets; + for (const auto &_ : +it) + { + *p++ = offset; + offset += hb_len_of (_); + } + *p = offset; + } + break; + case 3: + { + HBUINT24 *p = (HBUINT24 *) offsets; + for (const auto &_ : +it) + { + *p++ = offset; + offset += hb_len_of (_); + } + *p = offset; + } + break; + case 4: + { + HBUINT32 *p = (HBUINT32 *) offsets; + for (const auto &_ : +it) + { + *p++ = offset; + offset += hb_len_of (_); + } + *p = offset; + } + break; + default: + break; + } + + assert (offset == data_size + 1); + return_trace (true); + } + + template + static unsigned total_size (const Iterable &iterable, unsigned *data_size = nullptr, unsigned min_off_size = 0) + { + auto it = + hb_iter (iterable); + if (!it) + { + if (data_size) *data_size = 0; + return min_size; + } + + unsigned total = 0; + for (const auto &_ : +it) + total += hb_len_of (_); + + if (data_size) *data_size = total; + + unsigned off_size = (hb_bit_storage (total + 1) + 7) / 8; + off_size = hb_max(min_off_size, off_size); + + return min_size + HBUINT8::static_size + (hb_len (it) + 1) * off_size + total; + } + + void set_offset_at (unsigned int index, unsigned int offset) + { + assert (index <= count); + + unsigned int size = offSize; + const HBUINT8 *p = offsets; + switch (size) + { + case 1: ((HBUINT8 *) p)[index] = offset; break; + case 2: ((HBUINT16 *) p)[index] = offset; break; + case 3: ((HBUINT24 *) p)[index] = offset; break; + case 4: ((HBUINT32 *) p)[index] = offset; break; + default: return; + } + } + + private: + unsigned int offset_at (unsigned int index) const + { + assert (index <= count); + + unsigned int size = offSize; + const HBUINT8 *p = offsets; + switch (size) + { + case 1: return ((HBUINT8 *) p)[index]; + case 2: return ((HBUINT16 *) p)[index]; + case 3: return ((HBUINT24 *) p)[index]; + case 4: return ((HBUINT32 *) p)[index]; + default: return 0; + } + } + + const unsigned char *data_base () const + { return (const unsigned char *) this + min_size + offSize.static_size - 1 + offset_array_size (); } + public: + + hb_ubytes_t operator [] (unsigned int index) const + { + if (unlikely (index >= count)) return hb_ubytes_t (); + hb_barrier (); + unsigned offset0 = offset_at (index); + unsigned offset1 = offset_at (index + 1); + if (unlikely (offset1 < offset0 || offset1 > offset_at (count))) + return hb_ubytes_t (); + return hb_ubytes_t (data_base () + offset0, offset1 - offset0); + } + + unsigned int get_size () const + { + if (count) + return min_size + offSize.static_size + offset_array_size () + (offset_at (count) - 1); + return min_size; /* empty CFFIndex contains count only */ + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this) && + hb_barrier () && + (count == 0 || /* empty INDEX */ + (count < count + 1u && + c->check_struct (&offSize) && offSize >= 1 && offSize <= 4 && + c->check_array (offsets, offSize, count + 1u) && + c->check_range (data_base (), offset_at (count)))))); + } + + public: + COUNT count; /* Number of object data. Note there are (count+1) offsets */ + private: + HBUINT8 offSize; /* The byte size of each offset in the offsets array. */ + HBUINT8 offsets[HB_VAR_ARRAY]; + /* The array of (count + 1) offsets into objects array (1-base). */ + /* HBUINT8 data[HB_VAR_ARRAY]; Object data */ + public: + DEFINE_SIZE_MIN (COUNT::static_size); +}; +typedef CFFIndex CFF1Index; +typedef CFFIndex CFF2Index; + + +/* TupleValues */ +struct TupleValues +{ + enum packed_value_flag_t + { + VALUES_ARE_ZEROS = 0x80, + VALUES_ARE_BYTES = 0x00, + VALUES_ARE_WORDS = 0x40, + VALUES_ARE_LONGS = 0xC0, + VALUES_SIZE_MASK = 0xC0, + VALUE_RUN_COUNT_MASK = 0x3F + }; + + static unsigned compile (hb_array_t values, /* IN */ + hb_array_t encoded_bytes /* OUT */) + { + unsigned num_values = values.length; + unsigned encoded_len = 0; + unsigned i = 0; + while (i < num_values) + { + int val = values.arrayZ[i]; + if (val == 0) + encoded_len += encode_value_run_as_zeroes (i, encoded_bytes.sub_array (encoded_len), values); + else if (val >= -128 && val <= 127) + encoded_len += encode_value_run_as_bytes (i, encoded_bytes.sub_array (encoded_len), values); + else if (val >= -32768 && val <= 32767) + encoded_len += encode_value_run_as_words (i, encoded_bytes.sub_array (encoded_len), values); + else + encoded_len += encode_value_run_as_longs (i, encoded_bytes.sub_array (encoded_len), values); + } + return encoded_len; + } + + static unsigned encode_value_run_as_zeroes (unsigned& i, + hb_array_t encoded_bytes, + hb_array_t values) + { + unsigned num_values = values.length; + unsigned run_length = 0; + auto it = encoded_bytes.iter (); + unsigned encoded_len = 0; + while (i < num_values && values.arrayZ[i] == 0) + { + i++; + run_length++; + } + + while (run_length >= 64) + { + *it++ = char (VALUES_ARE_ZEROS | 63); + run_length -= 64; + encoded_len++; + } + + if (run_length) + { + *it++ = char (VALUES_ARE_ZEROS | (run_length - 1)); + encoded_len++; + } + return encoded_len; + } + + static unsigned encode_value_run_as_bytes (unsigned &i, + hb_array_t encoded_bytes, + hb_array_t values) + { + unsigned start = i; + unsigned num_values = values.length; + while (i < num_values) + { + int val = values.arrayZ[i]; + if (val > 127 || val < -128) + break; + + /* from fonttools: if there're 2 or more zeros in a sequence, + * it is better to start a new run to save bytes. */ + if (val == 0 && i + 1 < num_values && values.arrayZ[i+1] == 0) + break; + + i++; + } + unsigned run_length = i - start; + + unsigned encoded_len = 0; + auto it = encoded_bytes.iter (); + + while (run_length >= 64) + { + *it++ = (VALUES_ARE_BYTES | 63); + encoded_len++; + + for (unsigned j = 0; j < 64; j++) + { + *it++ = static_cast (values.arrayZ[start + j]); + encoded_len++; + } + + start += 64; + run_length -= 64; + } + + if (run_length) + { + *it++ = (VALUES_ARE_BYTES | (run_length - 1)); + encoded_len++; + + while (start < i) + { + *it++ = static_cast (values.arrayZ[start++]); + encoded_len++; + } + } + + return encoded_len; + } + + static unsigned encode_value_run_as_words (unsigned &i, + hb_array_t encoded_bytes, + hb_array_t values) + { + unsigned start = i; + unsigned num_values = values.length; + while (i < num_values) + { + int val = values.arrayZ[i]; + + /* start a new run for a single zero value*/ + if (val == 0) break; + + /* from fonttools: continue word-encoded run if there's only one + * single value in the range [-128, 127] because it is more compact. + * Only start a new run when there're 2 continuous such values. */ + if (val >= -128 && val <= 127 && + i + 1 < num_values && + values.arrayZ[i+1] >= -128 && values.arrayZ[i+1] <= 127) + break; + + i++; + } + + unsigned run_length = i - start; + auto it = encoded_bytes.iter (); + unsigned encoded_len = 0; + while (run_length >= 64) + { + *it++ = (VALUES_ARE_WORDS | 63); + encoded_len++; + + for (unsigned j = 0; j < 64; j++) + { + int16_t value_val = values.arrayZ[start + j]; + *it++ = static_cast (value_val >> 8); + *it++ = static_cast (value_val & 0xFF); + + encoded_len += 2; + } + + start += 64; + run_length -= 64; + } + + if (run_length) + { + *it++ = (VALUES_ARE_WORDS | (run_length - 1)); + encoded_len++; + while (start < i) + { + int16_t value_val = values.arrayZ[start++]; + *it++ = static_cast (value_val >> 8); + *it++ = static_cast (value_val & 0xFF); + + encoded_len += 2; + } + } + return encoded_len; + } + + static unsigned encode_value_run_as_longs (unsigned &i, + hb_array_t encoded_bytes, + hb_array_t values) + { + unsigned start = i; + unsigned num_values = values.length; + while (i < num_values) + { + int val = values.arrayZ[i]; + + if (val >= -32768 && val <= 32767) + break; + + i++; + } + + unsigned run_length = i - start; + auto it = encoded_bytes.iter (); + unsigned encoded_len = 0; + while (run_length >= 64) + { + *it++ = (VALUES_ARE_LONGS | 63); + encoded_len++; + + for (unsigned j = 0; j < 64; j++) + { + int32_t value_val = values.arrayZ[start + j]; + *it++ = static_cast (value_val >> 24); + *it++ = static_cast (value_val >> 16); + *it++ = static_cast (value_val >> 8); + *it++ = static_cast (value_val & 0xFF); + + encoded_len += 4; + } + + start += 64; + run_length -= 64; + } + + if (run_length) + { + *it++ = (VALUES_ARE_LONGS | (run_length - 1)); + encoded_len++; + while (start < i) + { + int32_t value_val = values.arrayZ[start++]; + *it++ = static_cast (value_val >> 24); + *it++ = static_cast (value_val >> 16); + *it++ = static_cast (value_val >> 8); + *it++ = static_cast (value_val & 0xFF); + + encoded_len += 4; + } + } + return encoded_len; + } + + template + static bool decompile (const HBUINT8 *&p /* IN/OUT */, + hb_vector_t &values /* IN/OUT */, + const HBUINT8 *end, + bool consume_all = false) + { + unsigned i = 0; + unsigned count = consume_all ? UINT_MAX : values.length; + if (consume_all) + values.alloc ((end - p) / 2); + while (i < count) + { + if (unlikely (p + 1 > end)) return consume_all; + unsigned control = *p++; + unsigned run_count = (control & VALUE_RUN_COUNT_MASK) + 1; + if (consume_all) + { + if (unlikely (!values.resize (values.length + run_count, false))) + return false; + } + unsigned stop = i + run_count; + if (unlikely (stop > count)) return false; + if ((control & VALUES_SIZE_MASK) == VALUES_ARE_ZEROS) + { + for (; i < stop; i++) + values.arrayZ[i] = 0; + } + else if ((control & VALUES_SIZE_MASK) == VALUES_ARE_WORDS) + { + if (unlikely (p + run_count * HBINT16::static_size > end)) return false; + for (; i < stop; i++) + { + values.arrayZ[i] = * (const HBINT16 *) p; + p += HBINT16::static_size; + } + } + else if ((control & VALUES_SIZE_MASK) == VALUES_ARE_LONGS) + { + if (unlikely (p + run_count * HBINT32::static_size > end)) return false; + for (; i < stop; i++) + { + values.arrayZ[i] = * (const HBINT32 *) p; + p += HBINT32::static_size; + } + } + else if ((control & VALUES_SIZE_MASK) == VALUES_ARE_BYTES) + { + if (unlikely (p + run_count > end)) return false; + for (; i < stop; i++) + { + values.arrayZ[i] = * (const HBINT8 *) p++; + } + } + } + return true; + } + + struct iter_t : hb_iter_with_fallback_t + { + iter_t (const unsigned char *p_, unsigned len_) + : p (p_), end (p_ + len_) + { if (ensure_run ()) read_value (); } + + private: + const unsigned char *p; + const unsigned char * const end; + int current_value = 0; + signed run_count = 0; + unsigned width = 0; + + bool ensure_run () + { + if (likely (run_count > 0)) return true; + + if (unlikely (p >= end)) + { + run_count = 0; + current_value = 0; + return false; + } + + unsigned control = *p++; + run_count = (control & VALUE_RUN_COUNT_MASK) + 1; + width = control & VALUES_SIZE_MASK; + switch (width) + { + case VALUES_ARE_ZEROS: width = 0; break; + case VALUES_ARE_BYTES: width = HBINT8::static_size; break; + case VALUES_ARE_WORDS: width = HBINT16::static_size; break; + case VALUES_ARE_LONGS: width = HBINT32::static_size; break; + default: assert (false); + } + + if (unlikely (p + run_count * width > end)) + { + run_count = 0; + current_value = 0; + return false; + } + + return true; + } + void read_value () + { + switch (width) + { + case 0: current_value = 0; break; + case 1: current_value = * (const HBINT8 *) p; break; + case 2: current_value = * (const HBINT16 *) p; break; + case 4: current_value = * (const HBINT32 *) p; break; + } + p += width; + } + + public: + + typedef int __item_t__; + __item_t__ __item__ () const + { return current_value; } + + bool __more__ () const { return run_count || p < end; } + void __next__ () + { + run_count--; + if (unlikely (!ensure_run ())) + return; + read_value (); + } + void __forward__ (unsigned n) + { + if (unlikely (!ensure_run ())) + return; + while (n) + { + unsigned i = hb_min (n, (unsigned) run_count); + run_count -= i; + n -= i; + p += (i - 1) * width; + if (unlikely (!ensure_run ())) + return; + read_value (); + } + } + bool operator != (const iter_t& o) const + { return p != o.p || run_count != o.run_count; } + iter_t __end__ () const + { + iter_t it (end, 0); + return it; + } + }; +}; + +struct TupleList : CFF2Index +{ + TupleValues::iter_t operator [] (unsigned i) const + { + auto bytes = CFF2Index::operator [] (i); + return TupleValues::iter_t (bytes.arrayZ, bytes.length); + } +}; + + } /* namespace OT */ diff --git a/libs/harfbuzz/src/hb-ot-cff-common.hh b/libs/harfbuzz/src/hb-ot-cff-common.hh index ae3b83a25..b49c0be51 100644 --- a/libs/harfbuzz/src/hb-ot-cff-common.hh +++ b/libs/harfbuzz/src/hb-ot-cff-common.hh @@ -41,268 +41,32 @@ using namespace OT; using objidx_t = hb_serialize_context_t::objidx_t; using whence_t = hb_serialize_context_t::whence_t; -/* utility macro */ -template -static inline const Type& StructAtOffsetOrNull (const void *P, unsigned int offset) -{ return offset ? StructAtOffset (P, offset) : Null (Type); } - -struct code_pair_t +/* CFF offsets can technically be negative */ +template +static inline const Type& StructAtOffsetOrNull (const void *P, int offset, hb_sanitize_context_t &sc, Ts&&... ds) { - hb_codepoint_t code; - hb_codepoint_t glyph; -}; - -using str_buff_t = hb_vector_t; -using str_buff_vec_t = hb_vector_t; - -/* CFF INDEX */ -template -struct CFFIndex -{ - unsigned int offset_array_size () const - { return offSize * (count + 1); } - - CFFIndex *copy (hb_serialize_context_t *c) const - { - TRACE_SERIALIZE (this); - unsigned int size = get_size (); - CFFIndex *out = c->allocate_size (size); - if (likely (out)) - memcpy (out, this, size); - return_trace (out); - } - - bool serialize (hb_serialize_context_t *c, - unsigned int offSize_, - const byte_str_array_t &byteArray) - { - TRACE_SERIALIZE (this); - - if (byteArray.length == 0) - { - COUNT *dest = c->allocate_min (); - if (unlikely (!dest)) return_trace (false); - *dest = 0; - return_trace (true); - } - - /* serialize CFFIndex header */ - if (unlikely (!c->extend_min (this))) return_trace (false); - this->count = byteArray.length; - this->offSize = offSize_; - if (unlikely (!c->allocate_size (offSize_ * (byteArray.length + 1)))) - return_trace (false); - - /* serialize indices */ - unsigned int offset = 1; - unsigned int i = 0; - for (; i < byteArray.length; i++) - { - set_offset_at (i, offset); - offset += byteArray[i].get_size (); - } - set_offset_at (i, offset); - - /* serialize data */ - for (unsigned int i = 0; i < byteArray.length; i++) - { - const hb_ubytes_t &bs = byteArray[i]; - unsigned char *dest = c->allocate_size (bs.length); - if (unlikely (!dest)) return_trace (false); - memcpy (dest, &bs[0], bs.length); - } - - return_trace (true); - } - - bool serialize (hb_serialize_context_t *c, - unsigned int offSize_, - const str_buff_vec_t &buffArray) - { - byte_str_array_t byteArray; - byteArray.init (); - byteArray.resize (buffArray.length); - for (unsigned int i = 0; i < byteArray.length; i++) - byteArray[i] = hb_ubytes_t (buffArray[i].arrayZ, buffArray[i].length); - bool result = this->serialize (c, offSize_, byteArray); - byteArray.fini (); - return result; - } - - template - bool serialize (hb_serialize_context_t *c, - Iterator it) - { - TRACE_SERIALIZE (this); - serialize_header(c, + it | hb_map ([] (const hb_ubytes_t &_) { return _.length; })); - for (const auto &_ : +it) - _.copy (c); - return_trace (true); - } - - bool serialize (hb_serialize_context_t *c, - const byte_str_array_t &byteArray) - { return serialize (c, + hb_iter (byteArray)); } - - bool serialize (hb_serialize_context_t *c, - const str_buff_vec_t &buffArray) - { - auto it = - + hb_iter (buffArray) - | hb_map ([] (const str_buff_t &_) { return hb_ubytes_t (_.arrayZ, _.length); }) - ; - return serialize (c, it); - } - - template - bool serialize_header (hb_serialize_context_t *c, - Iterator it) - { - TRACE_SERIALIZE (this); - - unsigned total = + it | hb_reduce (hb_add, 0); - unsigned off_size = (hb_bit_storage (total + 1) + 7) / 8; - - /* serialize CFFIndex header */ - if (unlikely (!c->extend_min (this))) return_trace (false); - this->count = it.len (); - if (!this->count) return_trace (true); - if (unlikely (!c->extend (this->offSize))) return_trace (false); - this->offSize = off_size; - if (unlikely (!c->allocate_size (off_size * (this->count + 1)))) - return_trace (false); - - /* serialize indices */ - unsigned int offset = 1; - unsigned int i = 0; - for (unsigned _ : +it) - { - CFFIndex::set_offset_at (i++, offset); - offset += _; - } - CFFIndex::set_offset_at (i, offset); - - return_trace (true); - } - - void set_offset_at (unsigned int index, unsigned int offset) - { - assert (index <= count); - HBUINT8 *p = offsets + offSize * index + offSize; - unsigned int size = offSize; - for (; size; size--) - { - --p; - *p = offset & 0xFF; - offset >>= 8; - } - } + if (!offset) return Null (Type); - private: - unsigned int offset_at (unsigned int index) const - { - assert (index <= count); - - unsigned int size = offSize; - const HBUINT8 *p = offsets + size * index; - unsigned int offset = 0; - for (; size; size--) - offset = (offset << 8) + *p++; - return offset; - } - - unsigned int length_at (unsigned int index) const - { - unsigned offset0 = offset_at (index); - unsigned offset1 = offset_at (index + 1); - if (unlikely (offset1 < offset0 || offset1 > offset_at (count))) - return 0; - return offset1 - offset0; - } - - const unsigned char *data_base () const - { return (const unsigned char *) this + min_size + offSize.static_size + offset_array_size (); } - public: - - hb_ubytes_t operator [] (unsigned int index) const - { - if (unlikely (index >= count)) return hb_ubytes_t (); - unsigned length = length_at (index); - if (unlikely (!length)) return hb_ubytes_t (); - return hb_ubytes_t (data_base () + offset_at (index) - 1, length); - } + const char *p = (const char *) P + offset; + if (!sc.check_point (p)) return Null (Type); - unsigned int get_size () const - { - if (count) - return min_size + offSize.static_size + offset_array_size () + (offset_at (count) - 1); - return min_size; /* empty CFFIndex contains count only */ - } + const Type &obj = *reinterpret_cast (p); + if (!obj.sanitize (&sc, std::forward (ds)...)) return Null (Type); - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this) && - (count == 0 || /* empty INDEX */ - (count < count + 1u && - c->check_struct (&offSize) && offSize >= 1 && offSize <= 4 && - c->check_array (offsets, offSize, count + 1u) && - c->check_array ((const HBUINT8*) data_base (), 1, offset_at (count) - 1))))); - } + return obj; +} - public: - COUNT count; /* Number of object data. Note there are (count+1) offsets */ - private: - HBUINT8 offSize; /* The byte size of each offset in the offsets array. */ - HBUINT8 offsets[HB_VAR_ARRAY]; - /* The array of (count + 1) offsets into objects array (1-base). */ - /* HBUINT8 data[HB_VAR_ARRAY]; Object data */ - public: - DEFINE_SIZE_MIN (COUNT::static_size); -}; -template -struct CFFIndexOf : CFFIndex +struct code_pair_t { - template - bool serialize (hb_serialize_context_t *c, - unsigned int offSize_, - const DATA *dataArray, - unsigned int dataArrayLen, - const hb_vector_t &dataSizeArray, - const PARAM1 ¶m1, - const PARAM2 ¶m2) - { - TRACE_SERIALIZE (this); - /* serialize CFFIndex header */ - if (unlikely (!c->extend_min (this))) return_trace (false); - this->count = dataArrayLen; - this->offSize = offSize_; - if (unlikely (!c->allocate_size (offSize_ * (dataArrayLen + 1)))) - return_trace (false); + unsigned code; + hb_codepoint_t glyph; +}; - /* serialize indices */ - unsigned int offset = 1; - unsigned int i = 0; - for (; i < dataArrayLen; i++) - { - CFFIndex::set_offset_at (i, offset); - offset += dataSizeArray[i]; - } - CFFIndex::set_offset_at (i, offset); - /* serialize data */ - for (unsigned int i = 0; i < dataArrayLen; i++) - { - TYPE *dest = c->start_embed (); - if (unlikely (!dest || !dest->serialize (c, dataArray[i], param1, param2))) - return_trace (false); - } - return_trace (true); - } -}; +using str_buff_t = hb_vector_t; +using str_buff_vec_t = hb_vector_t; +using glyph_to_sid_map_t = hb_vector_t; /* Top Dict, Font Dict, Private Dict */ struct Dict : UnsizedByteStr @@ -324,13 +88,12 @@ struct Dict : UnsizedByteStr template static bool serialize_int_op (hb_serialize_context_t *c, op_code_t op, V value, op_code_t intOp) { - // XXX: not sure why but LLVM fails to compile the following 'unlikely' macro invocation - if (/*unlikely*/ (!serialize_int (c, intOp, value))) + if (unlikely ((!serialize_int (c, intOp, value)))) return false; TRACE_SERIALIZE (this); /* serialize the opcode */ - HBUINT8 *p = c->allocate_size (OpCode_Size (op)); + HBUINT8 *p = c->allocate_size (OpCode_Size (op), false); if (unlikely (!p)) return_trace (false); if (Is_OpCode_ESC (op)) { @@ -380,7 +143,7 @@ struct table_info_t }; template -struct FDArray : CFFIndexOf +struct FDArray : CFFIndex { template bool serialize (hb_serialize_context_t *c, @@ -391,7 +154,11 @@ struct FDArray : CFFIndexOf /* serialize INDEX data */ hb_vector_t sizes; + if (it.is_random_access_iterator) + sizes.alloc (hb_len (it)); + c->push (); + char *data_base = c->head; + it | hb_map ([&] (const hb_pair_t &_) { @@ -401,10 +168,16 @@ struct FDArray : CFFIndexOf }) | hb_sink (sizes) ; + unsigned data_size = c->head - data_base; c->pop_pack (false); + if (unlikely (sizes.in_error ())) return_trace (false); + + /* It just happens that the above is packed right after the header below. + * Such a hack. */ + /* serialize INDEX header */ - return_trace (CFFIndex::serialize_header (c, hb_iter (sizes))); + return_trace (CFFIndex::serialize_header (c, hb_iter (sizes), data_size)); } }; @@ -415,15 +188,18 @@ struct FDSelect0 { TRACE_SANITIZE (this); if (unlikely (!(c->check_struct (this)))) return_trace (false); - for (unsigned int i = 0; i < c->get_num_glyphs (); i++) - if (unlikely (!fds[i].sanitize (c))) - return_trace (false); + hb_barrier (); + if (unlikely (!c->check_array (fds, c->get_num_glyphs ()))) + return_trace (false); return_trace (true); } - hb_codepoint_t get_fd (hb_codepoint_t glyph) const - { return (hb_codepoint_t) fds[glyph]; } + unsigned get_fd (hb_codepoint_t glyph) const + { return fds[glyph]; } + + hb_pair_t get_fd_range (hb_codepoint_t glyph) const + { return {fds[glyph], glyph + 1}; } unsigned int get_size (unsigned int num_glyphs) const { return HBUINT8::static_size * num_glyphs; } @@ -439,7 +215,9 @@ struct FDSelect3_4_Range bool sanitize (hb_sanitize_context_t *c, const void * /*nullptr*/, unsigned int fdcount) const { TRACE_SANITIZE (this); - return_trace (first < c->get_num_glyphs () && (fd < fdcount)); + return_trace (c->check_struct (this) && + hb_barrier () && + first < c->get_num_glyphs () && (fd < fdcount)); } GID_TYPE first; @@ -457,28 +235,47 @@ struct FDSelect3_4 bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const { TRACE_SANITIZE (this); - if (unlikely (!c->check_struct (this) || !ranges.sanitize (c, nullptr, fdcount) || - (nRanges () == 0) || ranges[0].first != 0)) + if (unlikely (!(c->check_struct (this) && + ranges.sanitize (c, nullptr, fdcount) && + hb_barrier () && + (nRanges () != 0) && + ranges[0].first == 0))) return_trace (false); for (unsigned int i = 1; i < nRanges (); i++) if (unlikely (ranges[i - 1].first >= ranges[i].first)) return_trace (false); - if (unlikely (!sentinel().sanitize (c) || (sentinel() != c->get_num_glyphs ()))) + if (unlikely (!(sentinel().sanitize (c) && + hb_barrier () && + (sentinel() == c->get_num_glyphs ())))) return_trace (false); return_trace (true); } - hb_codepoint_t get_fd (hb_codepoint_t glyph) const + static int _cmp_range (const void *_key, const void *_item) { - unsigned int i; - for (i = 1; i < nRanges (); i++) - if (glyph < ranges[i].first) - break; + hb_codepoint_t glyph = * (hb_codepoint_t *) _key; + FDSelect3_4_Range *range = (FDSelect3_4_Range *) _item; + + if (glyph < range[0].first) return -1; + if (glyph < range[1].first) return 0; + return +1; + } - return (hb_codepoint_t) ranges[i - 1].fd; + unsigned get_fd (hb_codepoint_t glyph) const + { + auto *range = hb_bsearch (glyph, &ranges[0], nRanges () - 1, sizeof (ranges[0]), _cmp_range); + return range ? range->fd : ranges[nRanges () - 1].fd; + } + + hb_pair_t get_fd_range (hb_codepoint_t glyph) const + { + auto *range = hb_bsearch (glyph, &ranges[0], nRanges () - 1, sizeof (ranges[0]), _cmp_range); + unsigned fd = range ? range->fd : ranges[nRanges () - 1].fd; + hb_codepoint_t end = range ? range[1].first : ranges[nRanges () - 1].first; + return {fd, end}; } GID_TYPE &nRanges () { return ranges.len; } @@ -501,9 +298,9 @@ struct FDSelect { TRACE_SERIALIZE (this); unsigned int size = src.get_size (num_glyphs); - FDSelect *dest = c->allocate_size (size); + FDSelect *dest = c->allocate_size (size, false); if (unlikely (!dest)) return_trace (false); - memcpy (dest, &src, size); + hb_memcpy (dest, &src, size); return_trace (true); } @@ -511,34 +308,47 @@ struct FDSelect { switch (format) { - case 0: return format.static_size + u.format0.get_size (num_glyphs); - case 3: return format.static_size + u.format3.get_size (); + case 0: hb_barrier (); return format.static_size + u.format0.get_size (num_glyphs); + case 3: hb_barrier (); return format.static_size + u.format3.get_size (); default:return 0; } } - hb_codepoint_t get_fd (hb_codepoint_t glyph) const + unsigned get_fd (hb_codepoint_t glyph) const { if (this == &Null (FDSelect)) return 0; switch (format) { - case 0: return u.format0.get_fd (glyph); - case 3: return u.format3.get_fd (glyph); + case 0: hb_barrier (); return u.format0.get_fd (glyph); + case 3: hb_barrier (); return u.format3.get_fd (glyph); default:return 0; } } + /* Returns pair of fd and one after last glyph in range. */ + hb_pair_t get_fd_range (hb_codepoint_t glyph) const + { + if (this == &Null (FDSelect)) return {0, 1}; + + switch (format) + { + case 0: hb_barrier (); return u.format0.get_fd_range (glyph); + case 3: hb_barrier (); return u.format3.get_fd_range (glyph); + default:return {0, 1}; + } + } bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const { TRACE_SANITIZE (this); if (unlikely (!c->check_struct (this))) return_trace (false); + hb_barrier (); switch (format) { - case 0: return_trace (u.format0.sanitize (c, fdcount)); - case 3: return_trace (u.format3.sanitize (c, fdcount)); + case 0: hb_barrier (); return_trace (u.format0.sanitize (c, fdcount)); + case 3: hb_barrier (); return_trace (u.format3.sanitize (c, fdcount)); default:return_trace (false); } } diff --git a/libs/harfbuzz/src/hb-ot-cff1-table.cc b/libs/harfbuzz/src/hb-ot-cff1-table.cc index bd9fe5d6d..66df28aae 100644 --- a/libs/harfbuzz/src/hb-ot-cff1-table.cc +++ b/libs/harfbuzz/src/hb-ot-cff1-table.cc @@ -422,8 +422,8 @@ bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph } else { - extents->x_bearing = font->em_scalef_x (bounds.min.x.to_real ()); - extents->width = font->em_scalef_x (bounds.max.x.to_real ()) - extents->x_bearing; + extents->x_bearing = roundf (bounds.min.x.to_real ()); + extents->width = roundf (bounds.max.x.to_real () - extents->x_bearing); } if (bounds.min.y >= bounds.max.y) { @@ -432,10 +432,12 @@ bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph } else { - extents->y_bearing = font->em_scalef_y (bounds.max.y.to_real ()); - extents->height = font->em_scalef_y (bounds.min.y.to_real ()) - extents->y_bearing; + extents->y_bearing = roundf (bounds.max.y.to_real ()); + extents->height = roundf (bounds.min.y.to_real () - extents->y_bearing); } + font->scale_glyph_extents (extents); + return true; } @@ -551,6 +553,15 @@ bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoin return true; } +bool OT::cff1::accelerator_t::paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const +{ + funcs->push_clip_glyph (data, glyph, font); + funcs->color (data, true, foreground); + funcs->pop_clip (data); + + return true; +} + bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const { #ifdef HB_NO_OT_FONT_CFF @@ -563,11 +574,11 @@ bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, h struct get_seac_param_t { - get_seac_param_t (const OT::cff1::accelerator_t *_cff) : cff (_cff) {} + get_seac_param_t (const OT::cff1::accelerator_subset_t *_cff) : cff (_cff) {} bool has_seac () const { return base && accent; } - const OT::cff1::accelerator_t *cff; + const OT::cff1::accelerator_subset_t *cff; hb_codepoint_t base = 0; hb_codepoint_t accent = 0; }; @@ -585,7 +596,7 @@ struct cff1_cs_opset_seac_t : cff1_cs_opset_t= num_glyphs))) return false; diff --git a/libs/harfbuzz/src/hb-ot-cff1-table.hh b/libs/harfbuzz/src/hb-ot-cff1-table.hh index 17b029661..b84d896e3 100644 --- a/libs/harfbuzz/src/hb-ot-cff1-table.hh +++ b/libs/harfbuzz/src/hb-ot-cff1-table.hh @@ -28,8 +28,9 @@ #define HB_OT_CFF1_TABLE_HH #include "hb-ot-cff-common.hh" -#include "hb-subset-cff1.hh" +#include "hb-subset-cff-common.hh" #include "hb-draw.hh" +#include "hb-paint.hh" #define HB_STRING_ARRAY_NAME cff1_std_strings #define HB_STRING_ARRAY_LIST "hb-ot-cff1-std-str.hh" @@ -43,17 +44,13 @@ namespace CFF { * CFF -- Compact Font Format (CFF) * https://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5176.CFF.pdf */ -#define HB_OT_TAG_cff1 HB_TAG('C','F','F',' ') +#define HB_OT_TAG_CFF1 HB_TAG('C','F','F',' ') #define CFF_UNDEF_SID CFF_UNDEF_CODE enum EncodingID { StandardEncoding = 0, ExpertEncoding = 1 }; enum CharsetID { ISOAdobeCharset = 0, ExpertCharset = 1, ExpertSubsetCharset = 2 }; -typedef CFFIndex CFF1Index; -template struct CFF1IndexOf : CFFIndexOf {}; - -typedef CFFIndex CFF1Index; typedef CFF1Index CFF1CharStrings; typedef Subrs CFF1Subrs; @@ -109,6 +106,7 @@ struct Encoding1 { hb_codepoint_t get_code (hb_codepoint_t glyph) const { + /* TODO: Add cache like get_sid. */ assert (glyph > 0); glyph--; for (unsigned int i = 0; i < nRanges (); i++) @@ -172,11 +170,7 @@ struct Encoding bool serialize (hb_serialize_context_t *c, const Encoding &src) { TRACE_SERIALIZE (this); - unsigned int size = src.get_size (); - Encoding *dest = c->allocate_size (size); - if (unlikely (!dest)) return_trace (false); - memcpy (dest, &src, size); - return_trace (true); + return_trace (c->embed (src)); } /* serialize a subset Encoding */ @@ -245,8 +239,8 @@ struct Encoding unsigned int size = min_size; switch (table_format ()) { - case 0: size += u.format0.get_size (); break; - case 1: size += u.format1.get_size (); break; + case 0: hb_barrier (); size += u.format0.get_size (); break; + case 1: hb_barrier (); size += u.format1.get_size (); break; } if (has_supplement ()) size += suppEncData ().get_size (); @@ -257,8 +251,8 @@ struct Encoding { switch (table_format ()) { - case 0: return u.format0.get_code (glyph); - case 1: return u.format1.get_code (glyph); + case 0: hb_barrier (); return u.format0.get_code (glyph); + case 1: hb_barrier (); return u.format1.get_code (glyph); default:return 0; } } @@ -278,11 +272,12 @@ struct Encoding TRACE_SANITIZE (this); if (unlikely (!c->check_struct (this))) return_trace (false); + hb_barrier (); switch (table_format ()) { - case 0: if (unlikely (!u.format0.sanitize (c))) { return_trace (false); } break; - case 1: if (unlikely (!u.format1.sanitize (c))) { return_trace (false); } break; + case 0: hb_barrier (); if (unlikely (!u.format0.sanitize (c))) { return_trace (false); } break; + case 1: hb_barrier (); if (unlikely (!u.format1.sanitize (c))) { return_trace (false); } break; default:return_trace (false); } return_trace (likely (!has_supplement () || suppEncData ().sanitize (c))); @@ -293,8 +288,8 @@ struct Encoding { switch (table_format ()) { - case 0: return StructAfter (u.format0.codes[u.format0.nCodes ()-1]); - case 1: return StructAfter (u.format1.ranges[u.format1.nRanges ()-1]); + case 0: hb_barrier (); return StructAfter (u.format0.codes[u.format0.nCodes ()-1]); + case 1: hb_barrier (); return StructAfter (u.format1.ranges[u.format1.nRanges ()-1]); default:return Null (CFF1SuppEncData); } } @@ -311,26 +306,29 @@ struct Encoding }; /* Charset */ -struct Charset0 { - bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs) const +struct Charset0 +{ + bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs, unsigned *num_charset_entries) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && sids[num_glyphs - 1].sanitize (c)); + if (num_charset_entries) *num_charset_entries = num_glyphs; + return_trace (sids.sanitize (c, num_glyphs - 1)); } hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned num_glyphs) const { if (unlikely (glyph >= num_glyphs)) return 0; - if (glyph == 0) + if (unlikely (glyph == 0)) return 0; else return sids[glyph - 1]; } - void collect_glyph_to_sid_map (hb_map_t *mapping, unsigned int num_glyphs) const + void collect_glyph_to_sid_map (glyph_to_sid_map_t *mapping, unsigned int num_glyphs) const { + mapping->resize (num_glyphs, false); for (hb_codepoint_t gid = 1; gid < num_glyphs; gid++) - mapping->set (gid, sids[gid - 1]); + mapping->arrayZ[gid] = {sids[gid - 1], gid}; } hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const @@ -346,13 +344,13 @@ struct Charset0 { return 0; } - unsigned int get_size (unsigned int num_glyphs) const + static unsigned int get_size (unsigned int num_glyphs) { assert (num_glyphs > 0); - return HBUINT16::static_size * (num_glyphs - 1); + return UnsizedArrayOf::get_size (num_glyphs - 1); } - HBUINT16 sids[HB_VAR_ARRAY]; + UnsizedArrayOf sids; DEFINE_SIZE_ARRAY(0, sids); }; @@ -373,38 +371,62 @@ struct Charset_Range { template struct Charset1_2 { - bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs) const + bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs, unsigned *num_charset_entries) const { TRACE_SANITIZE (this); - if (unlikely (!c->check_struct (this))) - return_trace (false); num_glyphs--; - for (unsigned int i = 0; num_glyphs > 0; i++) + unsigned i; + for (i = 0; num_glyphs > 0; i++) { - if (unlikely (!ranges[i].sanitize (c) || (num_glyphs < ranges[i].nLeft + 1))) + if (unlikely (!(ranges[i].sanitize (c) && + hb_barrier () && + (num_glyphs >= ranges[i].nLeft + 1)))) return_trace (false); num_glyphs -= (ranges[i].nLeft + 1); } + if (num_charset_entries) + *num_charset_entries = i; return_trace (true); } - hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned num_glyphs) const + hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned num_glyphs, + code_pair_t *cache = nullptr) const { if (unlikely (glyph >= num_glyphs)) return 0; - if (glyph == 0) return 0; - glyph--; - for (unsigned int i = 0;; i++) + unsigned i; + hb_codepoint_t start_glyph; + if (cache && likely (cache->glyph <= glyph)) { - if (glyph <= ranges[i].nLeft) - return (hb_codepoint_t) ranges[i].first + glyph; - glyph -= (ranges[i].nLeft + 1); + i = cache->code; + start_glyph = cache->glyph; + } + else + { + if (unlikely (glyph == 0)) return 0; + i = 0; + start_glyph = 1; + } + glyph -= start_glyph; + for (;; i++) + { + unsigned count = ranges[i].nLeft; + if (glyph <= count) + { + if (cache) + *cache = {i, start_glyph}; + return ranges[i].first + glyph; + } + count++; + start_glyph += count; + glyph -= count; } return 0; } - void collect_glyph_to_sid_map (hb_map_t *mapping, unsigned int num_glyphs) const + void collect_glyph_to_sid_map (glyph_to_sid_map_t *mapping, unsigned int num_glyphs) const { + mapping->resize (num_glyphs, false); hb_codepoint_t gid = 1; if (gid >= num_glyphs) return; @@ -412,8 +434,9 @@ struct Charset1_2 { { hb_codepoint_t sid = ranges[i].first; unsigned count = ranges[i].nLeft + 1; + unsigned last = gid + count; for (unsigned j = 0; j < count; j++) - mapping->set (gid++, sid++); + mapping->arrayZ[gid++] = {sid++, last - 1}; if (gid >= num_glyphs) break; @@ -438,21 +461,26 @@ struct Charset1_2 { unsigned int get_size (unsigned int num_glyphs) const { - unsigned int size = HBUINT8::static_size; - int glyph = (int)num_glyphs; + int glyph = (int) num_glyphs; + unsigned num_ranges = 0; assert (glyph > 0); glyph--; for (unsigned int i = 0; glyph > 0; i++) { glyph -= (ranges[i].nLeft + 1); - size += Charset_Range::static_size; + num_ranges++; } - return size; + return get_size_for_ranges (num_ranges); + } + + static unsigned int get_size_for_ranges (unsigned int num_ranges) + { + return UnsizedArrayOf >::get_size (num_ranges); } - Charset_Range ranges[HB_VAR_ARRAY]; + UnsizedArrayOf> ranges; DEFINE_SIZE_ARRAY (0, ranges); }; @@ -468,11 +496,7 @@ struct Charset bool serialize (hb_serialize_context_t *c, const Charset &src, unsigned int num_glyphs) { TRACE_SERIALIZE (this); - unsigned int size = src.get_size (num_glyphs); - Charset *dest = c->allocate_size (size); - if (unlikely (!dest)) return_trace (false); - memcpy (dest, &src, size); - return_trace (true); + return_trace (c->embed ((const char *) &src, src.get_size (num_glyphs))); } /* serialize a subset Charset */ @@ -489,13 +513,13 @@ struct Charset { case 0: { - Charset0 *fmt0 = c->allocate_size (Charset0::min_size + HBUINT16::static_size * (num_glyphs - 1)); + Charset0 *fmt0 = c->allocate_size (Charset0::get_size (num_glyphs), false); if (unlikely (!fmt0)) return_trace (false); unsigned int glyph = 0; for (unsigned int i = 0; i < sid_ranges.length; i++) { - hb_codepoint_t sid = sid_ranges[i].code; - for (int left = (int)sid_ranges[i].glyph; left >= 0; left--) + hb_codepoint_t sid = sid_ranges.arrayZ[i].code; + for (int left = (int)sid_ranges.arrayZ[i].glyph; left >= 0; left--) fmt0->sids[glyph++] = sid++; } } @@ -503,29 +527,35 @@ struct Charset case 1: { - Charset1 *fmt1 = c->allocate_size (Charset1::min_size + Charset1_Range::static_size * sid_ranges.length); + Charset1 *fmt1 = c->allocate_size (Charset1::get_size_for_ranges (sid_ranges.length), false); if (unlikely (!fmt1)) return_trace (false); + hb_codepoint_t all_glyphs = 0; for (unsigned int i = 0; i < sid_ranges.length; i++) { - if (unlikely (!(sid_ranges[i].glyph <= 0xFF))) - return_trace (false); - fmt1->ranges[i].first = sid_ranges[i].code; - fmt1->ranges[i].nLeft = sid_ranges[i].glyph; + auto &_ = sid_ranges.arrayZ[i]; + all_glyphs |= _.glyph; + fmt1->ranges[i].first = _.code; + fmt1->ranges[i].nLeft = _.glyph; } + if (unlikely (!(all_glyphs <= 0xFF))) + return_trace (false); } break; case 2: { - Charset2 *fmt2 = c->allocate_size (Charset2::min_size + Charset2_Range::static_size * sid_ranges.length); + Charset2 *fmt2 = c->allocate_size (Charset2::get_size_for_ranges (sid_ranges.length), false); if (unlikely (!fmt2)) return_trace (false); + hb_codepoint_t all_glyphs = 0; for (unsigned int i = 0; i < sid_ranges.length; i++) { - if (unlikely (!(sid_ranges[i].glyph <= 0xFFFF))) - return_trace (false); - fmt2->ranges[i].first = sid_ranges[i].code; - fmt2->ranges[i].nLeft = sid_ranges[i].glyph; + auto &_ = sid_ranges.arrayZ[i]; + all_glyphs |= _.glyph; + fmt2->ranges[i].first = _.code; + fmt2->ranges[i].nLeft = _.glyph; } + if (unlikely (!(all_glyphs <= 0xFFFF))) + return_trace (false); } break; @@ -537,31 +567,32 @@ struct Charset { switch (format) { - case 0: return min_size + u.format0.get_size (num_glyphs); - case 1: return min_size + u.format1.get_size (num_glyphs); - case 2: return min_size + u.format2.get_size (num_glyphs); + case 0: hb_barrier (); return min_size + u.format0.get_size (num_glyphs); + case 1: hb_barrier (); return min_size + u.format1.get_size (num_glyphs); + case 2: hb_barrier (); return min_size + u.format2.get_size (num_glyphs); default:return 0; } } - hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned int num_glyphs) const + hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned int num_glyphs, + code_pair_t *cache = nullptr) const { switch (format) { - case 0: return u.format0.get_sid (glyph, num_glyphs); - case 1: return u.format1.get_sid (glyph, num_glyphs); - case 2: return u.format2.get_sid (glyph, num_glyphs); + case 0: hb_barrier (); return u.format0.get_sid (glyph, num_glyphs); + case 1: hb_barrier (); return u.format1.get_sid (glyph, num_glyphs, cache); + case 2: hb_barrier (); return u.format2.get_sid (glyph, num_glyphs, cache); default:return 0; } } - void collect_glyph_to_sid_map (hb_map_t *mapping, unsigned int num_glyphs) const + void collect_glyph_to_sid_map (glyph_to_sid_map_t *mapping, unsigned int num_glyphs) const { switch (format) { - case 0: u.format0.collect_glyph_to_sid_map (mapping, num_glyphs); return; - case 1: u.format1.collect_glyph_to_sid_map (mapping, num_glyphs); return; - case 2: u.format2.collect_glyph_to_sid_map (mapping, num_glyphs); return; + case 0: hb_barrier (); u.format0.collect_glyph_to_sid_map (mapping, num_glyphs); return; + case 1: hb_barrier (); u.format1.collect_glyph_to_sid_map (mapping, num_glyphs); return; + case 2: hb_barrier (); u.format2.collect_glyph_to_sid_map (mapping, num_glyphs); return; default:return; } } @@ -570,24 +601,25 @@ struct Charset { switch (format) { - case 0: return u.format0.get_glyph (sid, num_glyphs); - case 1: return u.format1.get_glyph (sid, num_glyphs); - case 2: return u.format2.get_glyph (sid, num_glyphs); + case 0: hb_barrier (); return u.format0.get_glyph (sid, num_glyphs); + case 1: hb_barrier (); return u.format1.get_glyph (sid, num_glyphs); + case 2: hb_barrier (); return u.format2.get_glyph (sid, num_glyphs); default:return 0; } } - bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c, unsigned *num_charset_entries) const { TRACE_SANITIZE (this); if (unlikely (!c->check_struct (this))) return_trace (false); + hb_barrier (); switch (format) { - case 0: return_trace (u.format0.sanitize (c, c->get_num_glyphs ())); - case 1: return_trace (u.format1.sanitize (c, c->get_num_glyphs ())); - case 2: return_trace (u.format2.sanitize (c, c->get_num_glyphs ())); + case 0: hb_barrier (); return_trace (u.format0.sanitize (c, c->get_num_glyphs (), num_charset_entries)); + case 1: hb_barrier (); return_trace (u.format1.sanitize (c, c->get_num_glyphs (), num_charset_entries)); + case 2: hb_barrier (); return_trace (u.format2.sanitize (c, c->get_num_glyphs (), num_charset_entries)); default:return_trace (false); } } @@ -605,10 +637,10 @@ struct Charset struct CFF1StringIndex : CFF1Index { bool serialize (hb_serialize_context_t *c, const CFF1StringIndex &strings, - const hb_inc_bimap_t &sidmap) + const hb_vector_t &sidmap) { TRACE_SERIALIZE (this); - if (unlikely ((strings.count == 0) || (sidmap.get_population () == 0))) + if (unlikely ((strings.count == 0) || (sidmap.length == 0))) { if (unlikely (!c->extend_min (this->count))) return_trace (false); @@ -616,19 +648,15 @@ struct CFF1StringIndex : CFF1Index return_trace (true); } - byte_str_array_t bytesArray; - bytesArray.init (); - if (!bytesArray.resize (sidmap.get_population ())) - return_trace (false); - for (unsigned int i = 0; i < strings.count; i++) - { - hb_codepoint_t j = sidmap[i]; - if (j != HB_MAP_VALUE_INVALID) - bytesArray[j] = strings[i]; - } + if (unlikely (sidmap.in_error ())) return_trace (false); + + // Save this in a vector since serialize() iterates it twice. + hb_vector_t bytesArray (+ hb_iter (sidmap) + | hb_map (strings)); + + if (unlikely (bytesArray.in_error ())) return_trace (false); bool result = CFF1Index::serialize (c, bytesArray); - bytesArray.fini (); return_trace (result); } }; @@ -732,9 +760,9 @@ struct cff1_top_dict_values_t : top_dict_values_t unsigned int ros_supplement; unsigned int cidCount; - unsigned int EncodingOffset; - unsigned int CharsetOffset; - unsigned int FDSelectOffset; + int EncodingOffset; + int CharsetOffset; + int FDSelectOffset; table_info_t privateDictInfo; }; @@ -790,30 +818,30 @@ struct cff1_top_dict_opset_t : top_dict_opset_t break; case OpCode_Encoding: - dictval.EncodingOffset = env.argStack.pop_uint (); + dictval.EncodingOffset = env.argStack.pop_int (); env.clear_args (); if (unlikely (dictval.EncodingOffset == 0)) return; break; case OpCode_charset: - dictval.CharsetOffset = env.argStack.pop_uint (); + dictval.CharsetOffset = env.argStack.pop_int (); env.clear_args (); if (unlikely (dictval.CharsetOffset == 0)) return; break; case OpCode_FDSelect: - dictval.FDSelectOffset = env.argStack.pop_uint (); + dictval.FDSelectOffset = env.argStack.pop_int (); env.clear_args (); break; case OpCode_Private: - dictval.privateDictInfo.offset = env.argStack.pop_uint (); + dictval.privateDictInfo.offset = env.argStack.pop_int (); dictval.privateDictInfo.size = env.argStack.pop_uint (); env.clear_args (); break; default: - env.last_offset = env.str_ref.offset; + env.last_offset = env.str_ref.get_offset (); top_dict_opset_t::process_op (op, env, dictval); /* Record this operand below if stack is empty, otherwise done */ if (!env.argStack.is_empty ()) return; @@ -882,7 +910,7 @@ struct cff1_private_dict_values_base_t : dict_values_t } void fini () { dict_values_t::fini (); } - unsigned int subrsOffset; + int subrsOffset; const CFF1Subrs *localSubrs; }; @@ -903,8 +931,6 @@ struct cff1_private_dict_opset_t : dict_opset_t case OpCode_FamilyOtherBlues: case OpCode_StemSnapH: case OpCode_StemSnapV: - env.clear_args (); - break; case OpCode_StdHW: case OpCode_StdVW: case OpCode_BlueScale: @@ -916,11 +942,10 @@ struct cff1_private_dict_opset_t : dict_opset_t case OpCode_initialRandomSeed: case OpCode_defaultWidthX: case OpCode_nominalWidthX: - val.single_val = env.argStack.pop_num (); env.clear_args (); break; case OpCode_Subrs: - dictval.subrsOffset = env.argStack.pop_uint (); + dictval.subrsOffset = env.argStack.pop_int (); env.clear_args (); break; @@ -936,7 +961,7 @@ struct cff1_private_dict_opset_t : dict_opset_t } }; -struct cff1_private_dict_opset_subset : dict_opset_t +struct cff1_private_dict_opset_subset_t : dict_opset_t { static void process_op (op_code_t op, num_interp_env_t& env, cff1_private_dict_values_subset_t& dictval) { @@ -962,7 +987,7 @@ struct cff1_private_dict_opset_subset : dict_opset_t break; case OpCode_Subrs: - dictval.subrsOffset = env.argStack.pop_uint (); + dictval.subrsOffset = env.argStack.pop_int (); env.clear_args (); break; @@ -982,7 +1007,7 @@ typedef dict_interpreter_t cff1_font_dict_interpreter_t; typedef CFF1Index CFF1NameIndex; -typedef CFF1IndexOf CFF1TopDictIndex; +typedef CFF1Index CFF1TopDictIndex; struct cff1_font_dict_values_mod_t { @@ -1023,20 +1048,25 @@ using namespace CFF; struct cff1 { - static constexpr hb_tag_t tableTag = HB_OT_TAG_cff1; + static constexpr hb_tag_t tableTag = HB_OT_TAG_CFF1; bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && + hb_barrier () && likely (version.major == 1)); } template struct accelerator_templ_t { - void init (hb_face_t *face) + static constexpr hb_tag_t tableTag = cff1::tableTag; + + accelerator_templ_t (hb_face_t *face) { + if (!face) return; + topDict.init (); fontDicts.init (); privateDicts.init (); @@ -1050,40 +1080,43 @@ struct cff1 const OT::cff1 *cff = this->blob->template as (); if (cff == &Null (OT::cff1)) - { fini (); return; } + goto fail; nameIndex = &cff->nameIndex (cff); if ((nameIndex == &Null (CFF1NameIndex)) || !nameIndex->sanitize (&sc)) - { fini (); return; } + goto fail; + hb_barrier (); - topDictIndex = &StructAtOffset (nameIndex, nameIndex->get_size ()); - if ((topDictIndex == &Null (CFF1TopDictIndex)) || !topDictIndex->sanitize (&sc) || (topDictIndex->count == 0)) - { fini (); return; } + topDictIndex = &StructAtOffsetOrNull (nameIndex, nameIndex->get_size (), sc); + if (topDictIndex == &Null (CFF1TopDictIndex) || (topDictIndex->count == 0)) + goto fail; + hb_barrier (); { /* parse top dict */ const hb_ubytes_t topDictStr = (*topDictIndex)[0]; - if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; } + if (unlikely (!topDictStr.sanitize (&sc))) goto fail; + hb_barrier (); cff1_top_dict_interp_env_t env (topDictStr); cff1_top_dict_interpreter_t top_interp (env); - if (unlikely (!top_interp.interpret (topDict))) { fini (); return; } + if (unlikely (!top_interp.interpret (topDict))) goto fail; } if (is_predef_charset ()) charset = &Null (Charset); else { - charset = &StructAtOffsetOrNull (cff, topDict.CharsetOffset); - if (unlikely ((charset == &Null (Charset)) || !charset->sanitize (&sc))) { fini (); return; } + charset = &StructAtOffsetOrNull (cff, topDict.CharsetOffset, sc, &num_charset_entries); + if (unlikely (charset == &Null (Charset))) goto fail; } fdCount = 1; if (is_CID ()) { - fdArray = &StructAtOffsetOrNull (cff, topDict.FDArrayOffset); - fdSelect = &StructAtOffsetOrNull (cff, topDict.FDSelectOffset); - if (unlikely ((fdArray == &Null (CFF1FDArray)) || !fdArray->sanitize (&sc) || - (fdSelect == &Null (CFF1FDSelect)) || !fdSelect->sanitize (&sc, fdArray->count))) - { fini (); return; } + fdArray = &StructAtOffsetOrNull (cff, topDict.FDArrayOffset, sc); + fdSelect = &StructAtOffsetOrNull (cff, topDict.FDSelectOffset, sc, fdArray->count); + if (unlikely (fdArray == &Null (CFF1FDArray) || + fdSelect == &Null (CFF1FDSelect))) + goto fail; fdCount = fdArray->count; } @@ -1096,36 +1129,32 @@ struct cff1 encoding = &Null (Encoding); if (is_CID ()) { - if (unlikely (charset == &Null (Charset))) { fini (); return; } + if (unlikely (charset == &Null (Charset))) goto fail; } else { if (!is_predef_encoding ()) { - encoding = &StructAtOffsetOrNull (cff, topDict.EncodingOffset); - if (unlikely ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc))) { fini (); return; } + encoding = &StructAtOffsetOrNull (cff, topDict.EncodingOffset, sc); + if (unlikely (encoding == &Null (Encoding))) goto fail; } } - stringIndex = &StructAtOffset (topDictIndex, topDictIndex->get_size ()); - if ((stringIndex == &Null (CFF1StringIndex)) || !stringIndex->sanitize (&sc)) - { fini (); return; } - - globalSubrs = &StructAtOffset (stringIndex, stringIndex->get_size ()); - if ((globalSubrs != &Null (CFF1Subrs)) && !globalSubrs->sanitize (&sc)) - { fini (); return; } - - charStrings = &StructAtOffsetOrNull (cff, topDict.charStringsOffset); + stringIndex = &StructAtOffsetOrNull (topDictIndex, topDictIndex->get_size (), sc); + if (stringIndex == &Null (CFF1StringIndex)) + goto fail; - if ((charStrings == &Null (CFF1CharStrings)) || unlikely (!charStrings->sanitize (&sc))) - { fini (); return; } + globalSubrs = &StructAtOffsetOrNull (stringIndex, stringIndex->get_size (), sc); + charStrings = &StructAtOffsetOrNull (cff, topDict.charStringsOffset, sc); + if (charStrings == &Null (CFF1CharStrings)) + goto fail; num_glyphs = charStrings->count; if (num_glyphs != sc.get_num_glyphs ()) - { fini (); return; } + goto fail; if (unlikely (!privateDicts.resize (fdCount))) - { fini (); return; } + goto fail; for (unsigned int i = 0; i < fdCount; i++) privateDicts[i].init (); @@ -1135,27 +1164,25 @@ struct cff1 for (unsigned int i = 0; i < fdCount; i++) { hb_ubytes_t fontDictStr = (*fdArray)[i]; - if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; } + if (unlikely (!fontDictStr.sanitize (&sc))) goto fail; + hb_barrier (); cff1_font_dict_values_t *font; cff1_top_dict_interp_env_t env (fontDictStr); cff1_font_dict_interpreter_t font_interp (env); font = fontDicts.push (); - if (unlikely (fontDicts.in_error ())) { fini (); return; } + if (unlikely (fontDicts.in_error ())) goto fail; font->init (); - if (unlikely (!font_interp.interpret (*font))) { fini (); return; } + if (unlikely (!font_interp.interpret (*font))) goto fail; PRIVDICTVAL *priv = &privateDicts[i]; - const hb_ubytes_t privDictStr = StructAtOffset (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size); - if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; } + const hb_ubytes_t privDictStr = StructAtOffsetOrNull (cff, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size); + if (unlikely (privDictStr == (const unsigned char *) &Null (UnsizedByteStr))) goto fail; num_interp_env_t env2 (privDictStr); dict_interpreter_t priv_interp (env2); priv->init (); - if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; } + if (unlikely (!priv_interp.interpret (*priv))) goto fail; - priv->localSubrs = &StructAtOffsetOrNull (&privDictStr, priv->subrsOffset); - if (priv->localSubrs != &Null (CFF1Subrs) && - unlikely (!priv->localSubrs->sanitize (&sc))) - { fini (); return; } + priv->localSubrs = &StructAtOffsetOrNull (&privDictStr, priv->subrsOffset, sc); } } else /* non-CID */ @@ -1163,21 +1190,24 @@ struct cff1 cff1_top_dict_values_t *font = &topDict; PRIVDICTVAL *priv = &privateDicts[0]; - const hb_ubytes_t privDictStr = StructAtOffset (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size); - if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; } + const hb_ubytes_t privDictStr = StructAtOffsetOrNull (cff, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size); + if (unlikely (privDictStr == (const unsigned char *) &Null (UnsizedByteStr))) goto fail; num_interp_env_t env (privDictStr); dict_interpreter_t priv_interp (env); priv->init (); - if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; } + if (unlikely (!priv_interp.interpret (*priv))) goto fail; - priv->localSubrs = &StructAtOffsetOrNull (&privDictStr, priv->subrsOffset); - if (priv->localSubrs != &Null (CFF1Subrs) && - unlikely (!priv->localSubrs->sanitize (&sc))) - { fini (); return; } + priv->localSubrs = &StructAtOffsetOrNull (&privDictStr, priv->subrsOffset, sc); + hb_barrier (); } - } - void fini () + return; + + fail: + _fini (); + } + ~accelerator_templ_t () { _fini (); } + void _fini () { sc.end_processing (); topDict.fini (); @@ -1187,6 +1217,8 @@ struct cff1 blob = nullptr; } + hb_blob_t *get_blob () const { return blob; } + bool is_valid () const { return blob; } bool is_CID () const { return topDict.is_CID (); } @@ -1207,13 +1239,14 @@ struct cff1 bool is_predef_encoding () const { return topDict.EncodingOffset <= ExpertEncoding; } - hb_codepoint_t glyph_to_code (hb_codepoint_t glyph) const + hb_codepoint_t glyph_to_code (hb_codepoint_t glyph, + code_pair_t *glyph_to_sid_cache = nullptr) const { if (encoding != &Null (Encoding)) return encoding->get_code (glyph); else { - hb_codepoint_t sid = glyph_to_sid (glyph); + hb_codepoint_t sid = glyph_to_sid (glyph, glyph_to_sid_cache); if (sid == 0) return 0; hb_codepoint_t code = 0; switch (topDict.EncodingOffset) @@ -1231,12 +1264,14 @@ struct cff1 } } - hb_map_t *create_glyph_to_sid_map () const + glyph_to_sid_map_t *create_glyph_to_sid_map () const { if (charset != &Null (Charset)) { - hb_map_t *mapping = hb_map_create (); - mapping->set (0, 0); + auto *mapping = (glyph_to_sid_map_t *) hb_malloc (sizeof (glyph_to_sid_map_t)); + if (unlikely (!mapping)) return nullptr; + mapping = new (mapping) glyph_to_sid_map_t (); + mapping->push (code_pair_t {0, 1}); charset->collect_glyph_to_sid_map (mapping, num_glyphs); return mapping; } @@ -1244,10 +1279,11 @@ struct cff1 return nullptr; } - hb_codepoint_t glyph_to_sid (hb_codepoint_t glyph) const + hb_codepoint_t glyph_to_sid (hb_codepoint_t glyph, + code_pair_t *cache = nullptr) const { if (charset != &Null (Charset)) - return charset->get_sid (glyph, num_glyphs); + return charset->get_sid (glyph, num_glyphs, cache); else { hb_codepoint_t sid = 0; @@ -1295,10 +1331,10 @@ struct cff1 } protected: - hb_blob_t *blob = nullptr; hb_sanitize_context_t sc; public: + hb_blob_t *blob = nullptr; const Encoding *encoding = nullptr; const Charset *charset = nullptr; const CFF1NameIndex *nameIndex = nullptr; @@ -1316,19 +1352,17 @@ struct cff1 hb_vector_t privateDicts; unsigned int num_glyphs = 0; + unsigned int num_charset_entries = 0; }; struct accelerator_t : accelerator_templ_t { - accelerator_t (hb_face_t *face) + accelerator_t (hb_face_t *face) : SUPER (face) { - SUPER::init (face); - glyph_names.set_relaxed (nullptr); if (!is_valid ()) return; if (is_CID ()) return; - } ~accelerator_t () { @@ -1338,13 +1372,12 @@ struct cff1 names->fini (); hb_free (names); } - - SUPER::fini (); } bool get_glyph_name (hb_codepoint_t glyph, char *buf, unsigned int buf_len) const { + if (unlikely (glyph >= num_glyphs)) return false; if (unlikely (!is_valid ())) return false; if (is_CID()) return false; if (unlikely (!buf_len)) return true; @@ -1382,16 +1415,17 @@ struct cff1 hb_sorted_vector_t *names = glyph_names.get_acquire (); if (unlikely (!names)) { - names = (hb_sorted_vector_t *) hb_calloc (sizeof (hb_sorted_vector_t), 1); + names = (hb_sorted_vector_t *) hb_calloc (1, sizeof (hb_sorted_vector_t)); if (likely (names)) { names->init (); /* TODO */ /* fill glyph names */ + code_pair_t glyph_to_sid_cache {0, HB_CODEPOINT_INVALID}; for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++) { - hb_codepoint_t sid = glyph_to_sid (gid); + hb_codepoint_t sid = glyph_to_sid (gid, &glyph_to_sid_cache); gname_t gname; gname.sid = sid; if (sid < cff1_std_strings_length) @@ -1428,7 +1462,7 @@ struct cff1 } HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const; - HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const; + HB_INTERNAL bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const; HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const; private: @@ -1455,9 +1489,24 @@ struct cff1 typedef accelerator_templ_t SUPER; }; - struct accelerator_subset_t : accelerator_templ_t {}; + struct accelerator_subset_t : accelerator_templ_t + { + accelerator_subset_t (hb_face_t *face) : SUPER (face) {} + ~accelerator_subset_t () + { + if (cff_accelerator) + cff_subset_accelerator_t::destroy (cff_accelerator); + } + + HB_INTERNAL bool subset (hb_subset_context_t *c) const; + HB_INTERNAL bool serialize (hb_serialize_context_t *c, + struct cff1_subset_plan &plan) const; + HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const; - bool subset (hb_subset_context_t *c) const { return hb_subset_cff1 (c); } + mutable CFF::cff_subset_accelerator_t* cff_accelerator = nullptr; + + typedef accelerator_templ_t SUPER; + }; protected: HB_INTERNAL static hb_codepoint_t lookup_standard_encoding_for_code (hb_codepoint_t sid); @@ -1481,6 +1530,10 @@ struct cff1_accelerator_t : cff1::accelerator_t { cff1_accelerator_t (hb_face_t *face) : cff1::accelerator_t (face) {} }; +struct cff1_subset_accelerator_t : cff1::accelerator_subset_t { + cff1_subset_accelerator_t (hb_face_t *face) : cff1::accelerator_subset_t (face) {} +}; + } /* namespace OT */ #endif /* HB_OT_CFF1_TABLE_HH */ diff --git a/libs/harfbuzz/src/hb-ot-cff2-table.cc b/libs/harfbuzz/src/hb-ot-cff2-table.cc index 50c76daf9..e42217b4e 100644 --- a/libs/harfbuzz/src/hb-ot-cff2-table.cc +++ b/libs/harfbuzz/src/hb-ot-cff2-table.cc @@ -124,8 +124,8 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, } else { - extents->x_bearing = font->em_scalef_x (param.min_x.to_real ()); - extents->width = font->em_scalef_x (param.max_x.to_real ()) - extents->x_bearing; + extents->x_bearing = roundf (param.min_x.to_real ()); + extents->width = roundf (param.max_x.to_real () - extents->x_bearing); } if (param.min_y >= param.max_y) { @@ -134,10 +134,21 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, } else { - extents->y_bearing = font->em_scalef_y (param.max_y.to_real ()); - extents->height = font->em_scalef_y (param.min_y.to_real ()) - extents->y_bearing; + extents->y_bearing = roundf (param.max_y.to_real ()); + extents->height = roundf (param.min_y.to_real () - extents->y_bearing); } + font->scale_glyph_extents (extents); + + return true; +} + +bool OT::cff2::accelerator_t::paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const +{ + funcs->push_clip_glyph (data, glyph, font); + funcs->color (data, true, foreground); + funcs->pop_clip (data); + return true; } @@ -191,6 +202,11 @@ struct cff2_path_procs_path_t : path_procs_t {}; bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const +{ + return get_path_at (font, glyph, draw_session, hb_array (font->coords, font->num_coords)); +} + +bool OT::cff2::accelerator_t::get_path_at (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session, hb_array_t coords) const { #ifdef HB_NO_OT_FONT_CFF /* XXX Remove check when this code moves to .hh file. */ @@ -201,7 +217,7 @@ bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, h unsigned int fd = fdSelect->get_fd (glyph); const hb_ubytes_t str = (*charStrings)[glyph]; - cff2_cs_interp_env_t env (str, *this, fd, font->coords, font->num_coords); + cff2_cs_interp_env_t env (str, *this, fd, coords.arrayZ, coords.length); cff2_cs_interpreter_t interp (env); cff2_path_param_t param (font, draw_session); if (unlikely (!interp.interpret (param))) return false; diff --git a/libs/harfbuzz/src/hb-ot-cff2-table.hh b/libs/harfbuzz/src/hb-ot-cff2-table.hh index 746160dc8..c52c0511c 100644 --- a/libs/harfbuzz/src/hb-ot-cff2-table.hh +++ b/libs/harfbuzz/src/hb-ot-cff2-table.hh @@ -28,8 +28,9 @@ #define HB_OT_CFF2_TABLE_HH #include "hb-ot-cff-common.hh" -#include "hb-subset-cff2.hh" +#include "hb-subset-cff-common.hh" #include "hb-draw.hh" +#include "hb-paint.hh" namespace CFF { @@ -37,10 +38,7 @@ namespace CFF { * CFF2 -- Compact Font Format (CFF) Version 2 * https://docs.microsoft.com/en-us/typography/opentype/spec/cff2 */ -#define HB_OT_TAG_cff2 HB_TAG('C','F','F','2') - -typedef CFFIndex CFF2Index; -template struct CFF2IndexOf : CFFIndexOf {}; +#define HB_OT_TAG_CFF2 HB_TAG('C','F','F','2') typedef CFF2Index CFF2CharStrings; typedef Subrs CFF2Subrs; @@ -56,7 +54,7 @@ struct CFF2FDSelect unsigned int size = src.get_size (num_glyphs); CFF2FDSelect *dest = c->allocate_size (size); if (unlikely (!dest)) return_trace (false); - memcpy (dest, &src, size); + hb_memcpy (dest, &src, size); return_trace (true); } @@ -64,9 +62,9 @@ struct CFF2FDSelect { switch (format) { - case 0: return format.static_size + u.format0.get_size (num_glyphs); - case 3: return format.static_size + u.format3.get_size (); - case 4: return format.static_size + u.format4.get_size (); + case 0: hb_barrier (); return format.static_size + u.format0.get_size (num_glyphs); + case 3: hb_barrier (); return format.static_size + u.format3.get_size (); + case 4: hb_barrier (); return format.static_size + u.format4.get_size (); default:return 0; } } @@ -78,9 +76,9 @@ struct CFF2FDSelect switch (format) { - case 0: return u.format0.get_fd (glyph); - case 3: return u.format3.get_fd (glyph); - case 4: return u.format4.get_fd (glyph); + case 0: hb_barrier (); return u.format0.get_fd (glyph); + case 3: hb_barrier (); return u.format3.get_fd (glyph); + case 4: hb_barrier (); return u.format4.get_fd (glyph); default:return 0; } } @@ -90,12 +88,13 @@ struct CFF2FDSelect TRACE_SANITIZE (this); if (unlikely (!c->check_struct (this))) return_trace (false); + hb_barrier (); switch (format) { - case 0: return_trace (u.format0.sanitize (c, fdcount)); - case 3: return_trace (u.format3.sanitize (c, fdcount)); - case 4: return_trace (u.format4.sanitize (c, fdcount)); + case 0: hb_barrier (); return_trace (u.format0.sanitize (c, fdcount)); + case 3: hb_barrier (); return_trace (u.format3.sanitize (c, fdcount)); + case 4: hb_barrier (); return_trace (u.format4.sanitize (c, fdcount)); default:return_trace (false); } } @@ -110,30 +109,33 @@ struct CFF2FDSelect DEFINE_SIZE_MIN (2); }; -struct CFF2VariationStore +struct CFF2ItemVariationStore { bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this)) && c->check_range (&varStore, size) && varStore.sanitize (c)); + return_trace (c->check_struct (this) && + hb_barrier () && + c->check_range (&varStore, size) && + varStore.sanitize (c)); } - bool serialize (hb_serialize_context_t *c, const CFF2VariationStore *varStore) + bool serialize (hb_serialize_context_t *c, const CFF2ItemVariationStore *varStore) { TRACE_SERIALIZE (this); unsigned int size_ = varStore->get_size (); - CFF2VariationStore *dest = c->allocate_size (size_); + CFF2ItemVariationStore *dest = c->allocate_size (size_); if (unlikely (!dest)) return_trace (false); - memcpy (dest, varStore, size_); + hb_memcpy (dest, varStore, size_); return_trace (true); } unsigned int get_size () const { return HBUINT16::static_size + size; } HBUINT16 size; - VariationStore varStore; + ItemVariationStore varStore; - DEFINE_SIZE_MIN (2 + VariationStore::min_size); + DEFINE_SIZE_MIN (2 + ItemVariationStore::min_size); }; struct cff2_top_dict_values_t : top_dict_values_t<> @@ -146,8 +148,8 @@ struct cff2_top_dict_values_t : top_dict_values_t<> } void fini () { top_dict_values_t<>::fini (); } - unsigned int vstoreOffset; - unsigned int FDSelectOffset; + int vstoreOffset; + int FDSelectOffset; }; struct cff2_top_dict_opset_t : top_dict_opset_t<> @@ -165,11 +167,11 @@ struct cff2_top_dict_opset_t : top_dict_opset_t<> break; case OpCode_vstore: - dictval.vstoreOffset = env.argStack.pop_uint (); + dictval.vstoreOffset = env.argStack.pop_int (); env.clear_args (); break; case OpCode_FDSelect: - dictval.FDSelectOffset = env.argStack.pop_uint (); + dictval.FDSelectOffset = env.argStack.pop_int (); env.clear_args (); break; @@ -237,7 +239,7 @@ struct cff2_private_dict_values_base_t : dict_values_t } void fini () { dict_values_t::fini (); } - unsigned int subrsOffset; + int subrsOffset; const CFF2Subrs *localSubrs; unsigned int ivs; }; @@ -282,9 +284,6 @@ struct cff2_private_dict_opset_t : dict_opset_t case OpCode_BlueFuzz: case OpCode_ExpansionFactor: case OpCode_LanguageGroup: - val.single_val = env.argStack.pop_num (); - env.clear_args (); - break; case OpCode_BlueValues: case OpCode_OtherBlues: case OpCode_FamilyBlues: @@ -294,7 +293,7 @@ struct cff2_private_dict_opset_t : dict_opset_t env.clear_args (); break; case OpCode_Subrs: - dictval.subrsOffset = env.argStack.pop_uint (); + dictval.subrsOffset = env.argStack.pop_int (); env.clear_args (); break; case OpCode_vsindexdict: @@ -343,7 +342,7 @@ struct cff2_private_dict_opset_subset_t : dict_opset_t return; case OpCode_Subrs: - dictval.subrsOffset = env.argStack.pop_uint (); + dictval.subrsOffset = env.argStack.pop_int (); env.clear_args (); break; @@ -381,20 +380,25 @@ using namespace CFF; struct cff2 { - static constexpr hb_tag_t tableTag = HB_OT_TAG_cff2; + static constexpr hb_tag_t tableTag = HB_OT_TAG_CFF2; bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && + hb_barrier () && likely (version.major == 2)); } template struct accelerator_templ_t { + static constexpr hb_tag_t tableTag = cff2::tableTag; + accelerator_templ_t (hb_face_t *face) { + if (!face) return; + topDict.init (); fontDicts.init (); privateDicts.init (); @@ -413,23 +417,22 @@ struct cff2 { /* parse top dict */ hb_ubytes_t topDictStr = (cff2 + cff2->topDict).as_ubytes (cff2->topDictSize); if (unlikely (!topDictStr.sanitize (&sc))) goto fail; + hb_barrier (); num_interp_env_t env (topDictStr); cff2_top_dict_interpreter_t top_interp (env); topDict.init (); if (unlikely (!top_interp.interpret (topDict))) goto fail; } - globalSubrs = &StructAtOffset (cff2, cff2->topDict + cff2->topDictSize); - varStore = &StructAtOffsetOrNull (cff2, topDict.vstoreOffset); - charStrings = &StructAtOffsetOrNull (cff2, topDict.charStringsOffset); - fdArray = &StructAtOffsetOrNull (cff2, topDict.FDArrayOffset); - fdSelect = &StructAtOffsetOrNull (cff2, topDict.FDSelectOffset); - - if (((varStore != &Null (CFF2VariationStore)) && unlikely (!varStore->sanitize (&sc))) || - (charStrings == &Null (CFF2CharStrings)) || unlikely (!charStrings->sanitize (&sc)) || - (globalSubrs == &Null (CFF2Subrs)) || unlikely (!globalSubrs->sanitize (&sc)) || - (fdArray == &Null (CFF2FDArray)) || unlikely (!fdArray->sanitize (&sc)) || - (((fdSelect != &Null (CFF2FDSelect)) && unlikely (!fdSelect->sanitize (&sc, fdArray->count))))) + globalSubrs = &StructAtOffsetOrNull (cff2, cff2->topDict + cff2->topDictSize, sc); + varStore = &StructAtOffsetOrNull (cff2, topDict.vstoreOffset, sc); + charStrings = &StructAtOffsetOrNull (cff2, topDict.charStringsOffset, sc); + fdArray = &StructAtOffsetOrNull (cff2, topDict.FDArrayOffset, sc); + fdSelect = &StructAtOffsetOrNull (cff2, topDict.FDSelectOffset, sc, fdArray->count); + + if (charStrings == &Null (CFF2CharStrings) || + globalSubrs == &Null (CFF2Subrs) || + fdArray == &Null (CFF2FDArray)) goto fail; num_glyphs = charStrings->count; @@ -445,6 +448,7 @@ struct cff2 { const hb_ubytes_t fontDictStr = (*fdArray)[i]; if (unlikely (!fontDictStr.sanitize (&sc))) goto fail; + hb_barrier (); cff2_font_dict_values_t *font; num_interp_env_t env (fontDictStr); cff2_font_dict_interpreter_t font_interp (env); @@ -453,20 +457,16 @@ struct cff2 font->init (); if (unlikely (!font_interp.interpret (*font))) goto fail; - const hb_ubytes_t privDictStr = StructAtOffsetOrNull (cff2, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size); - if (unlikely (!privDictStr.sanitize (&sc))) goto fail; + const hb_ubytes_t privDictStr = StructAtOffsetOrNull (cff2, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size); + if (unlikely (privDictStr == (const unsigned char *) &Null (UnsizedByteStr))) goto fail; cff2_priv_dict_interp_env_t env2 (privDictStr); dict_interpreter_t priv_interp (env2); privateDicts[i].init (); if (unlikely (!priv_interp.interpret (privateDicts[i]))) goto fail; - privateDicts[i].localSubrs = &StructAtOffsetOrNull (&privDictStr[0], privateDicts[i].subrsOffset); - if (privateDicts[i].localSubrs != &Null (CFF2Subrs) && - unlikely (!privateDicts[i].localSubrs->sanitize (&sc))) - goto fail; + privateDicts[i].localSubrs = &StructAtOffsetOrNull (&privDictStr[0], privateDicts[i].subrsOffset, sc); } - return; fail: @@ -483,16 +483,23 @@ struct cff2 blob = nullptr; } + hb_vector_t *create_glyph_to_sid_map () const + { + return nullptr; + } + + hb_blob_t *get_blob () const { return blob; } + bool is_valid () const { return blob; } protected: - hb_blob_t *blob = nullptr; hb_sanitize_context_t sc; public: + hb_blob_t *blob = nullptr; cff2_top_dict_values_t topDict; const CFF2Subrs *globalSubrs = nullptr; - const CFF2VariationStore *varStore = nullptr; + const CFF2ItemVariationStore *varStore = nullptr; const CFF2CharStrings *charStrings = nullptr; const CFF2FDArray *fdArray = nullptr; const CFF2FDSelect *fdSelect = nullptr; @@ -511,12 +518,29 @@ struct cff2 HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const; + HB_INTERNAL bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const; HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const; + HB_INTERNAL bool get_path_at (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session, hb_array_t coords) const; }; - typedef accelerator_templ_t accelerator_subset_t; + struct accelerator_subset_t : accelerator_templ_t + { + accelerator_subset_t (hb_face_t *face) : SUPER (face) {} + ~accelerator_subset_t () + { + if (cff_accelerator) + cff_subset_accelerator_t::destroy (cff_accelerator); + } - bool subset (hb_subset_context_t *c) const { return hb_subset_cff2 (c); } + HB_INTERNAL bool subset (hb_subset_context_t *c) const; + HB_INTERNAL bool serialize (hb_serialize_context_t *c, + struct cff2_subset_plan &plan, + hb_array_t normalized_coords) const; + + mutable CFF::cff_subset_accelerator_t* cff_accelerator = nullptr; + + typedef accelerator_templ_t SUPER; + }; public: FixedVersion version; /* Version of CFF2 table. set to 0x0200u */ @@ -531,6 +555,10 @@ struct cff2_accelerator_t : cff2::accelerator_t { cff2_accelerator_t (hb_face_t *face) : cff2::accelerator_t (face) {} }; +struct cff2_subset_accelerator_t : cff2::accelerator_subset_t { + cff2_subset_accelerator_t (hb_face_t *face) : cff2::accelerator_subset_t (face) {} +}; + } /* namespace OT */ #endif /* HB_OT_CFF2_TABLE_HH */ diff --git a/libs/harfbuzz/src/hb-ot-cmap-table.hh b/libs/harfbuzz/src/hb-ot-cmap-table.hh index 09c9fe93f..0f1edce0b 100644 --- a/libs/harfbuzz/src/hb-ot-cmap-table.hh +++ b/libs/harfbuzz/src/hb-ot-cmap-table.hh @@ -31,6 +31,7 @@ #include "hb-ot-shaper-arabic-pua.hh" #include "hb-open-type.hh" #include "hb-set.hh" +#include "hb-cache.hh" /* * cmap -- Character to Glyph Index Mapping @@ -40,6 +41,148 @@ namespace OT { +static inline uint8_t unicode_to_macroman (hb_codepoint_t u) +{ + static const struct unicode_to_macroman_t + { + uint16_t unicode; + uint8_t macroman; + } + mapping[] = + { + { 0x00A0, 0xCA }, + { 0x00A1, 0xC1 }, + { 0x00A2, 0xA2 }, + { 0x00A3, 0xA3 }, + { 0x00A5, 0xB4 }, + { 0x00A7, 0xA4 }, + { 0x00A8, 0xAC }, + { 0x00A9, 0xA9 }, + { 0x00AA, 0xBB }, + { 0x00AB, 0xC7 }, + { 0x00AC, 0xC2 }, + { 0x00AE, 0xA8 }, + { 0x00AF, 0xF8 }, + { 0x00B0, 0xA1 }, + { 0x00B1, 0xB1 }, + { 0x00B4, 0xAB }, + { 0x00B5, 0xB5 }, + { 0x00B6, 0xA6 }, + { 0x00B7, 0xE1 }, + { 0x00B8, 0xFC }, + { 0x00BA, 0xBC }, + { 0x00BB, 0xC8 }, + { 0x00BF, 0xC0 }, + { 0x00C0, 0xCB }, + { 0x00C1, 0xE7 }, + { 0x00C2, 0xE5 }, + { 0x00C3, 0xCC }, + { 0x00C4, 0x80 }, + { 0x00C5, 0x81 }, + { 0x00C6, 0xAE }, + { 0x00C7, 0x82 }, + { 0x00C8, 0xE9 }, + { 0x00C9, 0x83 }, + { 0x00CA, 0xE6 }, + { 0x00CB, 0xE8 }, + { 0x00CC, 0xED }, + { 0x00CD, 0xEA }, + { 0x00CE, 0xEB }, + { 0x00CF, 0xEC }, + { 0x00D1, 0x84 }, + { 0x00D2, 0xF1 }, + { 0x00D3, 0xEE }, + { 0x00D4, 0xEF }, + { 0x00D5, 0xCD }, + { 0x00D6, 0x85 }, + { 0x00D8, 0xAF }, + { 0x00D9, 0xF4 }, + { 0x00DA, 0xF2 }, + { 0x00DB, 0xF3 }, + { 0x00DC, 0x86 }, + { 0x00DF, 0xA7 }, + { 0x00E0, 0x88 }, + { 0x00E1, 0x87 }, + { 0x00E2, 0x89 }, + { 0x00E3, 0x8B }, + { 0x00E4, 0x8A }, + { 0x00E5, 0x8C }, + { 0x00E6, 0xBE }, + { 0x00E7, 0x8D }, + { 0x00E8, 0x8F }, + { 0x00E9, 0x8E }, + { 0x00EA, 0x90 }, + { 0x00EB, 0x91 }, + { 0x00EC, 0x93 }, + { 0x00ED, 0x92 }, + { 0x00EE, 0x94 }, + { 0x00EF, 0x95 }, + { 0x00F1, 0x96 }, + { 0x00F2, 0x98 }, + { 0x00F3, 0x97 }, + { 0x00F4, 0x99 }, + { 0x00F5, 0x9B }, + { 0x00F6, 0x9A }, + { 0x00F7, 0xD6 }, + { 0x00F8, 0xBF }, + { 0x00F9, 0x9D }, + { 0x00FA, 0x9C }, + { 0x00FB, 0x9E }, + { 0x00FC, 0x9F }, + { 0x00FF, 0xD8 }, + { 0x0131, 0xF5 }, + { 0x0152, 0xCE }, + { 0x0153, 0xCF }, + { 0x0178, 0xD9 }, + { 0x0192, 0xC4 }, + { 0x02C6, 0xF6 }, + { 0x02C7, 0xFF }, + { 0x02D8, 0xF9 }, + { 0x02D9, 0xFA }, + { 0x02DA, 0xFB }, + { 0x02DB, 0xFE }, + { 0x02DC, 0xF7 }, + { 0x02DD, 0xFD }, + { 0x03A9, 0xBD }, + { 0x03C0, 0xB9 }, + { 0x2013, 0xD0 }, + { 0x2014, 0xD1 }, + { 0x2018, 0xD4 }, + { 0x2019, 0xD5 }, + { 0x201A, 0xE2 }, + { 0x201C, 0xD2 }, + { 0x201D, 0xD3 }, + { 0x201E, 0xE3 }, + { 0x2020, 0xA0 }, + { 0x2021, 0xE0 }, + { 0x2022, 0xA5 }, + { 0x2026, 0xC9 }, + { 0x2030, 0xE4 }, + { 0x2039, 0xDC }, + { 0x203A, 0xDD }, + { 0x2044, 0xDA }, + { 0x20AC, 0xDB }, + { 0x2122, 0xAA }, + { 0x2202, 0xB6 }, + { 0x2206, 0xC6 }, + { 0x220F, 0xB8 }, + { 0x2211, 0xB7 }, + { 0x221A, 0xC3 }, + { 0x221E, 0xB0 }, + { 0x222B, 0xBA }, + { 0x2248, 0xC5 }, + { 0x2260, 0xAD }, + { 0x2264, 0xB2 }, + { 0x2265, 0xB3 }, + { 0x25CA, 0xD7 }, + { 0xF8FF, 0xF0 }, + { 0xFB01, 0xDE }, + { 0xFB02, 0xDF }, + }; + auto *c = hb_bsearch (u, mapping, ARRAY_LENGTH (mapping), sizeof (mapping[0]), + _hb_cmp_operator); + return c ? c->macroman : 0; +} struct CmapSubtableFormat0 { @@ -276,10 +419,10 @@ struct CmapSubtableFormat4 } } writer(c); - writer.end_code_ = c->allocate_size (HBUINT16::static_size * segcount); - c->allocate_size (2); // padding - writer.start_code_ = c->allocate_size (HBUINT16::static_size * segcount); - writer.id_delta_ = c->allocate_size (HBINT16::static_size * segcount); + writer.end_code_ = c->allocate_size (HBUINT16::static_size * segcount, false); + (void) c->allocate_size (2); // padding + writer.start_code_ = c->allocate_size (HBUINT16::static_size * segcount, false); + writer.id_delta_ = c->allocate_size (HBINT16::static_size * segcount, false); if (unlikely (!writer.end_code_ || !writer.start_code_ || !writer.id_delta_)) return false; @@ -324,7 +467,7 @@ struct CmapSubtableFormat4 { auto format4_iter = + it - | hb_filter ([&] (const hb_pair_t _) + | hb_filter ([&] (const hb_codepoint_pair_t _) { return _.first <= 0xFFFF; }) ; @@ -334,7 +477,7 @@ struct CmapSubtableFormat4 if (unlikely (!c->extend_min (this))) return; this->format = 4; - hb_vector_t> cp_to_gid { + hb_vector_t cp_to_gid { format4_iter }; @@ -403,7 +546,7 @@ struct CmapSubtableFormat4 unsigned distance) const { if (k > last) return +1; - if (k < (&last)[distance]) return -1; + if (k < (&last)[distance]/*first*/) return -1; return 0; } HBUINT16 last; @@ -412,7 +555,7 @@ struct CmapSubtableFormat4 const HBUINT16 *found = hb_bsearch (codepoint, this->endCount, this->segCount, - 2, + sizeof (CustomRange), _hb_cmp_method, this->segCount + 1); if (unlikely (!found)) @@ -555,6 +698,7 @@ struct CmapSubtableFormat4 TRACE_SANITIZE (this); if (unlikely (!c->check_struct (this))) return_trace (false); + hb_barrier (); if (unlikely (!c->check_range (this, length))) { @@ -741,10 +885,11 @@ struct CmapSubtableLongSegmented unsigned num_glyphs) const { hb_codepoint_t last_end = 0; - for (unsigned i = 0; i < this->groups.len; i++) + unsigned count = this->groups.len; + for (unsigned i = 0; i < count; i++) { - hb_codepoint_t start = this->groups[i].startCharCode; - hb_codepoint_t end = hb_min ((hb_codepoint_t) this->groups[i].endCharCode, + hb_codepoint_t start = this->groups.arrayZ[i].startCharCode; + hb_codepoint_t end = hb_min ((hb_codepoint_t) this->groups.arrayZ[i].endCharCode, (hb_codepoint_t) HB_UNICODE_MAX); if (unlikely (start > end || start < last_end)) { // Range is not in order and is invalid, skip it. @@ -753,11 +898,10 @@ struct CmapSubtableLongSegmented last_end = end; - hb_codepoint_t gid = this->groups[i].glyphID; + hb_codepoint_t gid = this->groups.arrayZ[i].glyphID; if (!gid) { - /* Intention is: if (hb_is_same (T, CmapSubtableFormat13)) continue; */ - if (! T::group_get_glyph (this->groups[i], end)) continue; + if (T::formatNumber == 13) continue; start++; gid++; } @@ -765,11 +909,13 @@ struct CmapSubtableLongSegmented if (unlikely ((unsigned int) (gid + end - start) >= num_glyphs)) end = start + (hb_codepoint_t) num_glyphs - gid; + mapping->alloc (mapping->get_population () + end - start + 1); + + unicodes->add_range (start, end); for (unsigned cp = start; cp <= end; cp++) { - unicodes->add (cp); mapping->set (cp, gid); - gid++; + gid += T::increment; } } } @@ -793,6 +939,9 @@ struct CmapSubtableLongSegmented struct CmapSubtableFormat12 : CmapSubtableLongSegmented { + static constexpr int increment = 1; + static constexpr int formatNumber = 12; + static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group, hb_codepoint_t u) { return likely (group.startCharCode <= group.endCharCode) ? @@ -865,6 +1014,9 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented struct CmapSubtableFormat13 : CmapSubtableLongSegmented { + static constexpr int increment = 0; + static constexpr int formatNumber = 13; + static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group, hb_codepoint_t u HB_UNUSED) { return group.glyphID; } @@ -909,15 +1061,14 @@ struct DefaultUVS : SortedArray32Of hb_codepoint_t first = arrayZ[i].startUnicodeValue; hb_codepoint_t last = hb_min ((hb_codepoint_t) (first + arrayZ[i].additionalCount), (hb_codepoint_t) HB_UNICODE_MAX); - out->add_range (first, hb_min (last, 0x10FFFFu)); + out->add_range (first, last); } } DefaultUVS* copy (hb_serialize_context_t *c, const hb_set_t *unicodes) const { - DefaultUVS *out = c->start_embed (); - if (unlikely (!out)) return nullptr; + auto *out = c->start_embed (); auto snap = c->snapshot (); HBUINT32 len; @@ -925,37 +1076,74 @@ struct DefaultUVS : SortedArray32Of if (unlikely (!c->copy (len))) return nullptr; unsigned init_len = c->length (); - hb_codepoint_t lastCode = HB_MAP_VALUE_INVALID; - int count = -1; - - for (const UnicodeValueRange& _ : as_array ()) + if (this->len > unicodes->get_population () * hb_bit_storage ((unsigned) this->len)) { - for (const unsigned addcnt : hb_range ((unsigned) _.additionalCount + 1)) + hb_codepoint_t start = HB_SET_VALUE_INVALID; + hb_codepoint_t end = HB_SET_VALUE_INVALID; + + for (auto u : *unicodes) { - unsigned curEntry = (unsigned) _.startUnicodeValue + addcnt; - if (!unicodes->has (curEntry)) continue; - count += 1; - if (lastCode == HB_MAP_VALUE_INVALID) - lastCode = curEntry; - else if (lastCode + count != curEntry) + if (!as_array ().bsearch (u)) + continue; + if (start == HB_SET_VALUE_INVALID) { + start = u; + end = start - 1; + } + if (end + 1 != u || end - start == 255) + { UnicodeValueRange rec; - rec.startUnicodeValue = lastCode; - rec.additionalCount = count - 1; + rec.startUnicodeValue = start; + rec.additionalCount = end - start; c->copy (rec); - - lastCode = curEntry; - count = 0; + start = u; } + end = u; + } + if (start != HB_SET_VALUE_INVALID) + { + UnicodeValueRange rec; + rec.startUnicodeValue = start; + rec.additionalCount = end - start; + c->copy (rec); } - } - if (lastCode != HB_MAP_VALUE_INVALID) + } + else { - UnicodeValueRange rec; - rec.startUnicodeValue = lastCode; - rec.additionalCount = count; - c->copy (rec); + hb_codepoint_t lastCode = HB_SET_VALUE_INVALID; + int count = -1; + + for (const UnicodeValueRange& _ : *this) + { + hb_codepoint_t curEntry = (hb_codepoint_t) (_.startUnicodeValue - 1); + hb_codepoint_t end = curEntry + _.additionalCount + 2; + + for (; unicodes->next (&curEntry) && curEntry < end;) + { + count += 1; + if (lastCode == HB_SET_VALUE_INVALID) + lastCode = curEntry; + else if (lastCode + count != curEntry) + { + UnicodeValueRange rec; + rec.startUnicodeValue = lastCode; + rec.additionalCount = count - 1; + c->copy (rec); + + lastCode = curEntry; + count = 0; + } + } + } + + if (lastCode != HB_MAP_VALUE_INVALID) + { + UnicodeValueRange rec; + rec.startUnicodeValue = lastCode; + rec.additionalCount = count; + c->copy (rec); + } } if (c->length () - init_len == 0) @@ -1028,9 +1216,7 @@ struct NonDefaultUVS : SortedArray32Of const hb_set_t *glyphs_requested, const hb_map_t *glyph_map) const { - NonDefaultUVS *out = c->start_embed (); - if (unlikely (!out)) return nullptr; - + auto *out = c->start_embed (); auto it = + as_array () | hb_filter ([&] (const UVSMapping& _) @@ -1311,12 +1497,12 @@ struct CmapSubtable hb_codepoint_t *glyph) const { switch (u.format) { - case 0: return u.format0 .get_glyph (codepoint, glyph); - case 4: return u.format4 .get_glyph (codepoint, glyph); - case 6: return u.format6 .get_glyph (codepoint, glyph); - case 10: return u.format10.get_glyph (codepoint, glyph); - case 12: return u.format12.get_glyph (codepoint, glyph); - case 13: return u.format13.get_glyph (codepoint, glyph); + case 0: hb_barrier (); return u.format0 .get_glyph (codepoint, glyph); + case 4: hb_barrier (); return u.format4 .get_glyph (codepoint, glyph); + case 6: hb_barrier (); return u.format6 .get_glyph (codepoint, glyph); + case 10: hb_barrier (); return u.format10.get_glyph (codepoint, glyph); + case 12: hb_barrier (); return u.format12.get_glyph (codepoint, glyph); + case 13: hb_barrier (); return u.format13.get_glyph (codepoint, glyph); case 14: default: return false; } @@ -1324,12 +1510,12 @@ struct CmapSubtable void collect_unicodes (hb_set_t *out, unsigned int num_glyphs = UINT_MAX) const { switch (u.format) { - case 0: u.format0 .collect_unicodes (out); return; - case 4: u.format4 .collect_unicodes (out); return; - case 6: u.format6 .collect_unicodes (out); return; - case 10: u.format10.collect_unicodes (out); return; - case 12: u.format12.collect_unicodes (out, num_glyphs); return; - case 13: u.format13.collect_unicodes (out, num_glyphs); return; + case 0: hb_barrier (); u.format0 .collect_unicodes (out); return; + case 4: hb_barrier (); u.format4 .collect_unicodes (out); return; + case 6: hb_barrier (); u.format6 .collect_unicodes (out); return; + case 10: hb_barrier (); u.format10.collect_unicodes (out); return; + case 12: hb_barrier (); u.format12.collect_unicodes (out, num_glyphs); return; + case 13: hb_barrier (); u.format13.collect_unicodes (out, num_glyphs); return; case 14: default: return; } @@ -1340,12 +1526,12 @@ struct CmapSubtable unsigned num_glyphs = UINT_MAX) const { switch (u.format) { - case 0: u.format0 .collect_mapping (unicodes, mapping); return; - case 4: u.format4 .collect_mapping (unicodes, mapping); return; - case 6: u.format6 .collect_mapping (unicodes, mapping); return; - case 10: u.format10.collect_mapping (unicodes, mapping); return; - case 12: u.format12.collect_mapping (unicodes, mapping, num_glyphs); return; - case 13: u.format13.collect_mapping (unicodes, mapping, num_glyphs); return; + case 0: hb_barrier (); u.format0 .collect_mapping (unicodes, mapping); return; + case 4: hb_barrier (); u.format4 .collect_mapping (unicodes, mapping); return; + case 6: hb_barrier (); u.format6 .collect_mapping (unicodes, mapping); return; + case 10: hb_barrier (); u.format10.collect_mapping (unicodes, mapping); return; + case 12: hb_barrier (); u.format12.collect_mapping (unicodes, mapping, num_glyphs); return; + case 13: hb_barrier (); u.format13.collect_mapping (unicodes, mapping, num_glyphs); return; case 14: default: return; } @@ -1354,12 +1540,12 @@ struct CmapSubtable unsigned get_language () const { switch (u.format) { - case 0: return u.format0 .get_language (); - case 4: return u.format4 .get_language (); - case 6: return u.format6 .get_language (); - case 10: return u.format10.get_language (); - case 12: return u.format12.get_language (); - case 13: return u.format13.get_language (); + case 0: hb_barrier (); return u.format0 .get_language (); + case 4: hb_barrier (); return u.format4 .get_language (); + case 6: hb_barrier (); return u.format6 .get_language (); + case 10: hb_barrier (); return u.format10.get_language (); + case 12: hb_barrier (); return u.format12.get_language (); + case 13: hb_barrier (); return u.format13.get_language (); case 14: default: return 0; } @@ -1374,9 +1560,9 @@ struct CmapSubtable const void *base) { switch (format) { - case 4: return u.format4.serialize (c, it); - case 12: return u.format12.serialize (c, it); - case 14: return u.format14.serialize (c, plan->unicodes, plan->glyphs_requested, plan->glyph_map, base); + case 4: hb_barrier (); return u.format4.serialize (c, it); + case 12: hb_barrier (); return u.format12.serialize (c, it); + case 14: hb_barrier (); return u.format14.serialize (c, &plan->unicodes, &plan->glyphs_requested, plan->glyph_map, base); default: return; } } @@ -1385,14 +1571,15 @@ struct CmapSubtable { TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return_trace (false); + hb_barrier (); switch (u.format) { - case 0: return_trace (u.format0 .sanitize (c)); - case 4: return_trace (u.format4 .sanitize (c)); - case 6: return_trace (u.format6 .sanitize (c)); - case 10: return_trace (u.format10.sanitize (c)); - case 12: return_trace (u.format12.sanitize (c)); - case 13: return_trace (u.format13.sanitize (c)); - case 14: return_trace (u.format14.sanitize (c)); + case 0: hb_barrier (); return_trace (u.format0 .sanitize (c)); + case 4: hb_barrier (); return_trace (u.format4 .sanitize (c)); + case 6: hb_barrier (); return_trace (u.format6 .sanitize (c)); + case 10: hb_barrier (); return_trace (u.format10.sanitize (c)); + case 12: hb_barrier (); return_trace (u.format12.sanitize (c)); + case 13: hb_barrier (); return_trace (u.format13.sanitize (c)); + case 14: hb_barrier (); return_trace (u.format14.sanitize (c)); default:return_trace (true); } } @@ -1420,8 +1607,11 @@ struct EncodingRecord int ret; ret = platformID.cmp (other.platformID); if (ret) return ret; - ret = encodingID.cmp (other.encodingID); - if (ret) return ret; + if (other.encodingID != 0xFFFF) + { + ret = encodingID.cmp (other.encodingID); + if (ret) return ret; + } return 0; } @@ -1474,32 +1664,80 @@ struct EncodingRecord DEFINE_SIZE_STATIC (8); }; +struct cmap; + struct SubtableUnicodesCache { private: - const void* base; - hb_hashmap_t> cached_unicodes; + hb_blob_ptr_t base_blob; + const char* base; + hb_hashmap_t> cached_unicodes; public: + + static SubtableUnicodesCache* create (hb_blob_ptr_t source_table) + { + SubtableUnicodesCache* cache = + (SubtableUnicodesCache*) hb_malloc (sizeof(SubtableUnicodesCache)); + new (cache) SubtableUnicodesCache (source_table); + return cache; + } + + static void destroy (void* value) { + if (!value) return; + + SubtableUnicodesCache* cache = (SubtableUnicodesCache*) value; + cache->~SubtableUnicodesCache (); + hb_free (cache); + } + SubtableUnicodesCache(const void* cmap_base) - : base(cmap_base), cached_unicodes() {} + : base_blob(), + base ((const char*) cmap_base), + cached_unicodes () + {} + + SubtableUnicodesCache(hb_blob_ptr_t base_blob_) + : base_blob(base_blob_), + base ((const char *) base_blob.get()), + cached_unicodes () + {} - hb_set_t* set_for (const EncodingRecord* record) + ~SubtableUnicodesCache() { - if (!cached_unicodes.has ((intptr_t) record)) + base_blob.destroy (); + } + + bool same_base(const void* other) const + { + return other == (const void*) base; + } + + const hb_set_t* set_for (const EncodingRecord* record, + SubtableUnicodesCache& mutable_cache) const + { + if (cached_unicodes.has ((unsigned) ((const char *) record - base))) + return cached_unicodes.get ((unsigned) ((const char *) record - base)); + + return mutable_cache.set_for (record); + } + + const hb_set_t* set_for (const EncodingRecord* record) + { + if (!cached_unicodes.has ((unsigned) ((const char *) record - base))) { hb_set_t *s = hb_set_create (); if (unlikely (s->in_error ())) return hb_set_get_empty (); - + (base+record->subtable).collect_unicodes (s); - if (unlikely (!cached_unicodes.set ((intptr_t) record, hb::unique_ptr {s}))) + if (unlikely (!cached_unicodes.set ((unsigned) ((const char *) record - base), hb::unique_ptr {s}))) return hb_set_get_empty (); return s; } - return cached_unicodes.get ((intptr_t) record); + return cached_unicodes.get ((unsigned) ((const char *) record - base)); } }; @@ -1523,13 +1761,30 @@ struct cmap { static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap; + + static SubtableUnicodesCache* create_filled_cache(hb_blob_ptr_t source_table) { + const cmap* cmap = source_table.get(); + auto it = + + hb_iter (cmap->encodingRecord) + | hb_filter ([&](const EncodingRecord& _) { + return cmap::filter_encoding_records_for_subset (cmap, _); + }) + ; + + SubtableUnicodesCache* cache = SubtableUnicodesCache::create(source_table); + for (const EncodingRecord& _ : it) + cache->set_for(&_); // populate the cache for this encoding record. + + return cache; + } + template bool serialize (hb_serialize_context_t *c, Iterator it, EncodingRecIter encodingrec_iter, const void *base, - const hb_subset_plan_t *plan, + hb_subset_plan_t *plan, bool drop_format_4 = false) { if (unlikely (!c->extend_min ((*this)))) return false; @@ -1538,7 +1793,14 @@ struct cmap unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0; auto snap = c->snapshot (); - SubtableUnicodesCache unicodes_cache (base); + SubtableUnicodesCache local_unicodes_cache (base); + const SubtableUnicodesCache* unicodes_cache = &local_unicodes_cache; + + if (plan->accelerator && + plan->accelerator->cmap_cache && + plan->accelerator->cmap_cache->same_base (base)) + unicodes_cache = plan->accelerator->cmap_cache; + for (const EncodingRecord& _ : encodingrec_iter) { if (c->in_error ()) @@ -1547,7 +1809,7 @@ struct cmap unsigned format = (base+_.subtable).u.format; if (format != 4 && format != 12 && format != 14) continue; - hb_set_t* unicodes_set = unicodes_cache.set_for (&_); + const hb_set_t* unicodes_set = unicodes_cache->set_for (&_, local_unicodes_cache); if (!drop_format_4 && format == 4) { @@ -1566,7 +1828,13 @@ struct cmap else if (format == 12) { - if (_can_drop (_, *unicodes_set, base, unicodes_cache, + it | hb_map (hb_first), encodingrec_iter)) continue; + if (_can_drop (_, + *unicodes_set, + base, + *unicodes_cache, + local_unicodes_cache, + + it | hb_map (hb_first), encodingrec_iter)) + continue; c->copy (_, + it | hb_filter (*unicodes_set, hb_first), 12u, base, plan, &format12objidx); } else if (format == 14) c->copy (_, it, 14u, base, plan, &format14objidx); @@ -1585,7 +1853,8 @@ struct cmap bool _can_drop (const EncodingRecord& cmap12, const hb_set_t& cmap12_unicodes, const void* base, - SubtableUnicodesCache& unicodes_cache, + const SubtableUnicodesCache& unicodes_cache, + SubtableUnicodesCache& local_unicodes_cache, Iterator subset_unicodes, EncodingRecordIterator encoding_records) { @@ -1616,7 +1885,7 @@ struct cmap || (base+_.subtable).get_language() != target_language) continue; - hb_set_t* sibling_unicodes = unicodes_cache.set_for (&_); + const hb_set_t* sibling_unicodes = unicodes_cache.set_for (&_, local_unicodes_cache); auto cmap12 = + subset_unicodes | hb_filter (cmap12_unicodes); auto sibling = + subset_unicodes | hb_filter (*sibling_unicodes); @@ -1649,21 +1918,12 @@ struct cmap TRACE_SUBSET (this); cmap *cmap_prime = c->serializer->start_embed (); - if (unlikely (!c->serializer->check_success (cmap_prime))) return_trace (false); auto encodingrec_iter = + hb_iter (encodingRecord) - | hb_filter ([&] (const EncodingRecord& _) - { - if ((_.platformID == 0 && _.encodingID == 3) || - (_.platformID == 0 && _.encodingID == 4) || - (_.platformID == 3 && _.encodingID == 1) || - (_.platformID == 3 && _.encodingID == 10) || - (this + _.subtable).u.format == 14) - return true; - - return false; - }) + | hb_filter ([&](const EncodingRecord& _) { + return cmap::filter_encoding_records_for_subset (this, _); + }) ; if (unlikely (!encodingrec_iter.len ())) return_trace (false); @@ -1688,16 +1948,24 @@ struct cmap auto it = + c->plan->unicode_to_new_gid_list.iter () - | hb_filter ([&] (const hb_pair_t _) + | hb_filter ([&] (const hb_codepoint_pair_t _) { return (_.second != HB_MAP_VALUE_INVALID); }) ; - return_trace (cmap_prime->serialize (c->serializer, it, encodingrec_iter, this, c->plan)); + return_trace (cmap_prime->serialize (c->serializer, + it, + encodingrec_iter, + this, + c->plan)); } - const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const + const CmapSubtable *find_best_subtable (bool *symbol = nullptr, + bool *mac = nullptr, + bool *macroman = nullptr) const { if (symbol) *symbol = false; + if (mac) *mac = false; + if (macroman) *macroman = false; const CmapSubtable *subtable; @@ -1722,17 +1990,33 @@ struct cmap if ((subtable = this->find_subtable (0, 1))) return subtable; if ((subtable = this->find_subtable (0, 0))) return subtable; + /* MacRoman subtable. */ + if ((subtable = this->find_subtable (1, 0))) + { + if (mac) *mac = true; + if (macroman) *macroman = true; + return subtable; + } + /* Any other Mac subtable; we just map ASCII for these. */ + if ((subtable = this->find_subtable (1, 0xFFFF))) + { + if (mac) *mac = true; + return subtable; + } + /* Meh. */ return &Null (CmapSubtable); } struct accelerator_t { + using cache_t = hb_cache_t<21, 16, 8, true>; + accelerator_t (hb_face_t *face) { this->table = hb_sanitize_context_t ().reference_table (face); - bool symbol; - this->subtable = table->find_best_subtable (&symbol); + bool symbol, mac, macroman; + this->subtable = table->find_best_subtable (&symbol, &mac, ¯oman); this->subtable_uvs = &Null (CmapSubtableFormat14); { const CmapSubtable *st = table->find_subtable (0, 5); @@ -1741,6 +2025,7 @@ struct cmap } this->get_glyph_data = subtable; +#ifndef HB_NO_CMAP_LEGACY_SUBTABLES if (unlikely (symbol)) { switch ((unsigned) face->table.OS2->get_font_page ()) { @@ -1760,7 +2045,16 @@ struct cmap break; } } + else if (unlikely (macroman)) + { + this->get_glyph_funcZ = get_glyph_from_macroman; + } + else if (unlikely (mac)) + { + this->get_glyph_funcZ = get_glyph_from_ascii; + } else +#endif { switch (subtable->u.format) { /* Accelerate format 4 and format 12. */ @@ -1782,26 +2076,43 @@ struct cmap } ~accelerator_t () { this->table.destroy (); } + inline bool _cached_get (hb_codepoint_t unicode, + hb_codepoint_t *glyph, + cache_t *cache) const + { + unsigned v; + if (cache && cache->get (unicode, &v)) + { + *glyph = v; + return true; + } + bool ret = this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph); + + if (cache && ret) + cache->set (unicode, *glyph); + return ret; + } + bool get_nominal_glyph (hb_codepoint_t unicode, - hb_codepoint_t *glyph) const + hb_codepoint_t *glyph, + cache_t *cache = nullptr) const { if (unlikely (!this->get_glyph_funcZ)) return false; - return this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph); + return _cached_get (unicode, glyph, cache); } + unsigned int get_nominal_glyphs (unsigned int count, const hb_codepoint_t *first_unicode, unsigned int unicode_stride, hb_codepoint_t *first_glyph, - unsigned int glyph_stride) const + unsigned int glyph_stride, + cache_t *cache = nullptr) const { if (unlikely (!this->get_glyph_funcZ)) return 0; - hb_cmap_get_glyph_func_t get_glyph_funcZ = this->get_glyph_funcZ; - const void *get_glyph_data = this->get_glyph_data; - unsigned int done; for (done = 0; - done < count && get_glyph_funcZ (get_glyph_data, *first_unicode, first_glyph); + done < count && _cached_get (*first_unicode, first_glyph, cache); done++) { first_unicode = &StructAtOffsetUnaligned (first_unicode, unicode_stride); @@ -1812,7 +2123,8 @@ struct cmap bool get_variation_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector, - hb_codepoint_t *glyph) const + hb_codepoint_t *glyph, + cache_t *cache = nullptr) const { switch (this->subtable_uvs->get_glyph_variant (unicode, variation_selector, @@ -1823,7 +2135,7 @@ struct cmap case GLYPH_VARIANT_USE_DEFAULT: break; } - return get_nominal_glyph (unicode, glyph); + return get_nominal_glyph (unicode, glyph, cache); } void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const @@ -1867,6 +2179,28 @@ struct cmap return false; } + template + HB_INTERNAL static bool get_glyph_from_ascii (const void *obj, + hb_codepoint_t codepoint, + hb_codepoint_t *glyph) + { + const Type *typed_obj = (const Type *) obj; + return codepoint < 0x80 && typed_obj->get_glyph (codepoint, glyph); + } + + template + HB_INTERNAL static bool get_glyph_from_macroman (const void *obj, + hb_codepoint_t codepoint, + hb_codepoint_t *glyph) + { + if (get_glyph_from_ascii (obj, codepoint, glyph)) + return true; + + const Type *typed_obj = (const Type *) obj; + unsigned c = unicode_to_macroman (codepoint); + return c && typed_obj->get_glyph (c, glyph); + } + private: hb_nonnull_ptr_t subtable; hb_nonnull_ptr_t subtable_uvs; @@ -1896,38 +2230,30 @@ struct cmap return &(this+result.subtable); } - const EncodingRecord *find_encodingrec (unsigned int platform_id, - unsigned int encoding_id) const - { - EncodingRecord key; - key.platformID = platform_id; - key.encodingID = encoding_id; - - return encodingRecord.as_array ().bsearch (key); - } - - bool find_subtable (unsigned format) const - { - auto it = - + hb_iter (encodingRecord) - | hb_map (&EncodingRecord::subtable) - | hb_map (hb_add (this)) - | hb_filter ([&] (const CmapSubtable& _) { return _.u.format == format; }) - ; - - return it.len (); - } - public: bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && + hb_barrier () && likely (version == 0) && encodingRecord.sanitize (c, this)); } + private: + + static bool filter_encoding_records_for_subset(const cmap* cmap, + const EncodingRecord& _) + { + return + (_.platformID == 0 && _.encodingID == 3) || + (_.platformID == 0 && _.encodingID == 4) || + (_.platformID == 3 && _.encodingID == 1) || + (_.platformID == 3 && _.encodingID == 10) || + (cmap + _.subtable).u.format == 14; + } + protected: HBUINT16 version; /* Table version number (0). */ SortedArray16Of diff --git a/libs/harfbuzz/src/hb-ot-color-colr-table.hh b/libs/harfbuzz/src/hb-ot-color-colr-table.hh deleted file mode 100644 index 908bf550f..000000000 --- a/libs/harfbuzz/src/hb-ot-color-colr-table.hh +++ /dev/null @@ -1,1544 +0,0 @@ -/* - * Copyright © 2018 Ebrahim Byagowi - * Copyright © 2020 Google, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Calder Kitagawa - */ - -#ifndef HB_OT_COLOR_COLR_TABLE_HH -#define HB_OT_COLOR_COLR_TABLE_HH - -#include "hb-open-type.hh" -#include "hb-ot-layout-common.hh" -#include "hb-ot-var-common.hh" - -/* - * COLR -- Color - * https://docs.microsoft.com/en-us/typography/opentype/spec/colr - */ -#define HB_OT_TAG_COLR HB_TAG('C','O','L','R') - -#ifndef HB_COLRV1_MAX_NESTING_LEVEL -#define HB_COLRV1_MAX_NESTING_LEVEL 100 -#endif - -#ifndef COLRV1_ENABLE_SUBSETTING -#define COLRV1_ENABLE_SUBSETTING 1 -#endif - -namespace OT { - -struct COLR; -struct hb_colrv1_closure_context_t : - hb_dispatch_context_t -{ - template - return_t dispatch (const T &obj) - { - if (unlikely (nesting_level_left == 0)) - return hb_empty_t (); - - if (paint_visited (&obj)) - return hb_empty_t (); - - nesting_level_left--; - obj.closurev1 (this); - nesting_level_left++; - return hb_empty_t (); - } - static return_t default_return_value () { return hb_empty_t (); } - - bool paint_visited (const void *paint) - { - hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) paint - (uintptr_t) base); - if (visited_paint.in_error() || visited_paint.has (delta)) - return true; - - visited_paint.add (delta); - return false; - } - - const COLR* get_colr_table () const - { return reinterpret_cast (base); } - - void add_glyph (unsigned glyph_id) - { glyphs->add (glyph_id); } - - void add_layer_indices (unsigned first_layer_index, unsigned num_of_layers) - { layer_indices->add_range (first_layer_index, first_layer_index + num_of_layers - 1); } - - void add_palette_index (unsigned palette_index) - { palette_indices->add (palette_index); } - - public: - const void *base; - hb_set_t visited_paint; - hb_set_t *glyphs; - hb_set_t *layer_indices; - hb_set_t *palette_indices; - unsigned nesting_level_left; - - hb_colrv1_closure_context_t (const void *base_, - hb_set_t *glyphs_, - hb_set_t *layer_indices_, - hb_set_t *palette_indices_, - unsigned nesting_level_left_ = HB_COLRV1_MAX_NESTING_LEVEL) : - base (base_), - glyphs (glyphs_), - layer_indices (layer_indices_), - palette_indices (palette_indices_), - nesting_level_left (nesting_level_left_) - {} -}; - -struct LayerRecord -{ - operator hb_ot_color_layer_t () const { return {glyphId, colorIdx}; } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this)); - } - - public: - HBGlyphID16 glyphId; /* Glyph ID of layer glyph */ - Index colorIdx; /* Index value to use with a - * selected color palette. - * An index value of 0xFFFF - * is a special case indicating - * that the text foreground - * color (defined by a - * higher-level client) should - * be used and shall not be - * treated as actual index - * into CPAL ColorRecord array. */ - public: - DEFINE_SIZE_STATIC (4); -}; - -struct BaseGlyphRecord -{ - int cmp (hb_codepoint_t g) const - { return g < glyphId ? -1 : g > glyphId ? 1 : 0; } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this)); - } - - public: - HBGlyphID16 glyphId; /* Glyph ID of reference glyph */ - HBUINT16 firstLayerIdx; /* Index (from beginning of - * the Layer Records) to the - * layer record. There will be - * numLayers consecutive entries - * for this base glyph. */ - HBUINT16 numLayers; /* Number of color layers - * associated with this glyph */ - public: - DEFINE_SIZE_STATIC (6); -}; - -template -struct Variable -{ - Variable* copy (hb_serialize_context_t *c) const - { - TRACE_SERIALIZE (this); - return_trace (c->embed (this)); - } - - void closurev1 (hb_colrv1_closure_context_t* c) const - { value.closurev1 (c); } - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - if (!value.subset (c)) return_trace (false); - return_trace (c->serializer->embed (varIdxBase)); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && value.sanitize (c)); - } - - protected: - T value; - VarIdx varIdxBase; - public: - DEFINE_SIZE_STATIC (4 + T::static_size); -}; - -template -struct NoVariable -{ - NoVariable* copy (hb_serialize_context_t *c) const - { - TRACE_SERIALIZE (this); - return_trace (c->embed (this)); - } - - void closurev1 (hb_colrv1_closure_context_t* c) const - { value.closurev1 (c); } - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - return_trace (value.subset (c)); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && value.sanitize (c)); - } - - T value; - public: - DEFINE_SIZE_STATIC (T::static_size); -}; - -// Color structures - -struct ColorStop -{ - void closurev1 (hb_colrv1_closure_context_t* c) const - { c->add_palette_index (paletteIndex); } - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - auto *out = c->serializer->embed (*this); - if (unlikely (!out)) return_trace (false); - return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes->get (paletteIndex), - HB_SERIALIZE_ERROR_INT_OVERFLOW)); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this)); - } - - F2DOT14 stopOffset; - HBUINT16 paletteIndex; - F2DOT14 alpha; - public: - DEFINE_SIZE_STATIC (2 + 2 * F2DOT14::static_size); -}; - -struct Extend : HBUINT8 -{ - enum { - EXTEND_PAD = 0, - EXTEND_REPEAT = 1, - EXTEND_REFLECT = 2, - }; - public: - DEFINE_SIZE_STATIC (1); -}; - -template class Var> -struct ColorLine -{ - void closurev1 (hb_colrv1_closure_context_t* c) const - { - for (const auto &stop : stops.iter ()) - stop.closurev1 (c); - } - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - auto *out = c->serializer->start_embed (this); - if (unlikely (!out)) return_trace (false); - if (unlikely (!c->serializer->extend_min (out))) return_trace (false); - - if (!c->serializer->check_assign (out->extend, extend, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false); - if (!c->serializer->check_assign (out->stops.len, stops.len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW)) return_trace (false); - - for (const auto& stop : stops.iter ()) - { - if (!stop.subset (c)) return_trace (false); - } - return_trace (true); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - stops.sanitize (c)); - } - - Extend extend; - Array16Of> stops; - public: - DEFINE_SIZE_ARRAY_SIZED (3, stops); -}; - -// Composition modes - -// Compositing modes are taken from https://www.w3.org/TR/compositing-1/ -// NOTE: a brief audit of major implementations suggests most support most -// or all of the specified modes. -struct CompositeMode : HBUINT8 -{ - enum { - // Porter-Duff modes - // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators - COMPOSITE_CLEAR = 0, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_clear - COMPOSITE_SRC = 1, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_src - COMPOSITE_DEST = 2, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dst - COMPOSITE_SRC_OVER = 3, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcover - COMPOSITE_DEST_OVER = 4, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstover - COMPOSITE_SRC_IN = 5, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcin - COMPOSITE_DEST_IN = 6, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstin - COMPOSITE_SRC_OUT = 7, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcout - COMPOSITE_DEST_OUT = 8, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstout - COMPOSITE_SRC_ATOP = 9, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcatop - COMPOSITE_DEST_ATOP = 10, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstatop - COMPOSITE_XOR = 11, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_xor - COMPOSITE_PLUS = 12, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_plus - - // Blend modes - // https://www.w3.org/TR/compositing-1/#blending - COMPOSITE_SCREEN = 13, // https://www.w3.org/TR/compositing-1/#blendingscreen - COMPOSITE_OVERLAY = 14, // https://www.w3.org/TR/compositing-1/#blendingoverlay - COMPOSITE_DARKEN = 15, // https://www.w3.org/TR/compositing-1/#blendingdarken - COMPOSITE_LIGHTEN = 16, // https://www.w3.org/TR/compositing-1/#blendinglighten - COMPOSITE_COLOR_DODGE = 17, // https://www.w3.org/TR/compositing-1/#blendingcolordodge - COMPOSITE_COLOR_BURN = 18, // https://www.w3.org/TR/compositing-1/#blendingcolorburn - COMPOSITE_HARD_LIGHT = 19, // https://www.w3.org/TR/compositing-1/#blendinghardlight - COMPOSITE_SOFT_LIGHT = 20, // https://www.w3.org/TR/compositing-1/#blendingsoftlight - COMPOSITE_DIFFERENCE = 21, // https://www.w3.org/TR/compositing-1/#blendingdifference - COMPOSITE_EXCLUSION = 22, // https://www.w3.org/TR/compositing-1/#blendingexclusion - COMPOSITE_MULTIPLY = 23, // https://www.w3.org/TR/compositing-1/#blendingmultiply - - // Modes that, uniquely, do not operate on components - // https://www.w3.org/TR/compositing-1/#blendingnonseparable - COMPOSITE_HSL_HUE = 24, // https://www.w3.org/TR/compositing-1/#blendinghue - COMPOSITE_HSL_SATURATION = 25, // https://www.w3.org/TR/compositing-1/#blendingsaturation - COMPOSITE_HSL_COLOR = 26, // https://www.w3.org/TR/compositing-1/#blendingcolor - COMPOSITE_HSL_LUMINOSITY = 27, // https://www.w3.org/TR/compositing-1/#blendingluminosity - }; - public: - DEFINE_SIZE_STATIC (1); -}; - -struct Affine2x3 -{ - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this)); - } - - F16DOT16 xx; - F16DOT16 yx; - F16DOT16 xy; - F16DOT16 yy; - F16DOT16 dx; - F16DOT16 dy; - public: - DEFINE_SIZE_STATIC (6 * F16DOT16::static_size); -}; - -struct PaintColrLayers -{ - void closurev1 (hb_colrv1_closure_context_t* c) const; - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - auto *out = c->serializer->embed (this); - if (unlikely (!out)) return_trace (false); - return_trace (c->serializer->check_assign (out->firstLayerIndex, c->plan->colrv1_layers->get (firstLayerIndex), - HB_SERIALIZE_ERROR_INT_OVERFLOW)); - - return_trace (true); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this)); - } - - HBUINT8 format; /* format = 1 */ - HBUINT8 numLayers; - HBUINT32 firstLayerIndex; /* index into COLRv1::layerList */ - public: - DEFINE_SIZE_STATIC (6); -}; - -struct PaintSolid -{ - void closurev1 (hb_colrv1_closure_context_t* c) const - { c->add_palette_index (paletteIndex); } - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - auto *out = c->serializer->embed (*this); - if (unlikely (!out)) return_trace (false); - return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes->get (paletteIndex), - HB_SERIALIZE_ERROR_INT_OVERFLOW)); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this)); - } - - HBUINT8 format; /* format = 2(noVar) or 3(Var)*/ - HBUINT16 paletteIndex; - F2DOT14 alpha; - public: - DEFINE_SIZE_STATIC (3 + F2DOT14::static_size); -}; - -template class Var> -struct PaintLinearGradient -{ - void closurev1 (hb_colrv1_closure_context_t* c) const - { (this+colorLine).closurev1 (c); } - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - auto *out = c->serializer->embed (this); - if (unlikely (!out)) return_trace (false); - - return_trace (out->colorLine.serialize_subset (c, colorLine, this)); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && colorLine.sanitize (c, this)); - } - - HBUINT8 format; /* format = 4(noVar) or 5 (Var) */ - Offset24To> colorLine; /* Offset (from beginning of PaintLinearGradient - * table) to ColorLine subtable. */ - FWORD x0; - FWORD y0; - FWORD x1; - FWORD y1; - FWORD x2; - FWORD y2; - public: - DEFINE_SIZE_STATIC (4 + 6 * FWORD::static_size); -}; - -template class Var> -struct PaintRadialGradient -{ - void closurev1 (hb_colrv1_closure_context_t* c) const - { (this+colorLine).closurev1 (c); } - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - auto *out = c->serializer->embed (this); - if (unlikely (!out)) return_trace (false); - - return_trace (out->colorLine.serialize_subset (c, colorLine, this)); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && colorLine.sanitize (c, this)); - } - - HBUINT8 format; /* format = 6(noVar) or 7 (Var) */ - Offset24To> colorLine; /* Offset (from beginning of PaintRadialGradient - * table) to ColorLine subtable. */ - FWORD x0; - FWORD y0; - UFWORD radius0; - FWORD x1; - FWORD y1; - UFWORD radius1; - public: - DEFINE_SIZE_STATIC (4 + 6 * FWORD::static_size); -}; - -template class Var> -struct PaintSweepGradient -{ - void closurev1 (hb_colrv1_closure_context_t* c) const - { (this+colorLine).closurev1 (c); } - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - auto *out = c->serializer->embed (this); - if (unlikely (!out)) return_trace (false); - - return_trace (out->colorLine.serialize_subset (c, colorLine, this)); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && colorLine.sanitize (c, this)); - } - - HBUINT8 format; /* format = 8(noVar) or 9 (Var) */ - Offset24To> colorLine; /* Offset (from beginning of PaintSweepGradient - * table) to ColorLine subtable. */ - FWORD centerX; - FWORD centerY; - F2DOT14 startAngle; - F2DOT14 endAngle; - public: - DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size + 2 * F2DOT14::static_size); -}; - -struct Paint; - -// Paint a non-COLR glyph, filled as indicated by paint. -struct PaintGlyph -{ - void closurev1 (hb_colrv1_closure_context_t* c) const; - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - auto *out = c->serializer->embed (this); - if (unlikely (!out)) return_trace (false); - - if (! c->serializer->check_assign (out->gid, c->plan->glyph_map->get (gid), - HB_SERIALIZE_ERROR_INT_OVERFLOW)) - return_trace (false); - - return_trace (out->paint.serialize_subset (c, paint, this)); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && paint.sanitize (c, this)); - } - - HBUINT8 format; /* format = 10 */ - Offset24To paint; /* Offset (from beginning of PaintGlyph table) to Paint subtable. */ - HBUINT16 gid; - public: - DEFINE_SIZE_STATIC (6); -}; - -struct PaintColrGlyph -{ - void closurev1 (hb_colrv1_closure_context_t* c) const; - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - auto *out = c->serializer->embed (this); - if (unlikely (!out)) return_trace (false); - - return_trace (c->serializer->check_assign (out->gid, c->plan->glyph_map->get (gid), - HB_SERIALIZE_ERROR_INT_OVERFLOW)); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this)); - } - - HBUINT8 format; /* format = 11 */ - HBUINT16 gid; - public: - DEFINE_SIZE_STATIC (3); -}; - -template class Var> -struct PaintTransform -{ - HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - auto *out = c->serializer->embed (this); - if (unlikely (!out)) return_trace (false); - if (!out->transform.serialize_copy (c->serializer, transform, this)) return_trace (false); - return_trace (out->src.serialize_subset (c, src, this)); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - src.sanitize (c, this) && - transform.sanitize (c, this)); - } - - HBUINT8 format; /* format = 12(noVar) or 13 (Var) */ - Offset24To src; /* Offset (from beginning of PaintTransform table) to Paint subtable. */ - Offset24To> transform; - public: - DEFINE_SIZE_STATIC (7); -}; - -struct PaintTranslate -{ - HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - auto *out = c->serializer->embed (this); - if (unlikely (!out)) return_trace (false); - - return_trace (out->src.serialize_subset (c, src, this)); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && src.sanitize (c, this)); - } - - HBUINT8 format; /* format = 14(noVar) or 15 (Var) */ - Offset24To src; /* Offset (from beginning of PaintTranslate table) to Paint subtable. */ - FWORD dx; - FWORD dy; - public: - DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size); -}; - -struct PaintScale -{ - HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - auto *out = c->serializer->embed (this); - if (unlikely (!out)) return_trace (false); - - return_trace (out->src.serialize_subset (c, src, this)); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && src.sanitize (c, this)); - } - - HBUINT8 format; /* format = 16 (noVar) or 17(Var) */ - Offset24To src; /* Offset (from beginning of PaintScale table) to Paint subtable. */ - F2DOT14 scaleX; - F2DOT14 scaleY; - public: - DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size); -}; - -struct PaintScaleAroundCenter -{ - HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - auto *out = c->serializer->embed (this); - if (unlikely (!out)) return_trace (false); - - return_trace (out->src.serialize_subset (c, src, this)); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && src.sanitize (c, this)); - } - - HBUINT8 format; /* format = 18 (noVar) or 19(Var) */ - Offset24To src; /* Offset (from beginning of PaintScaleAroundCenter table) to Paint subtable. */ - F2DOT14 scaleX; - F2DOT14 scaleY; - FWORD centerX; - FWORD centerY; - public: - DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size + 2 * FWORD::static_size); -}; - -struct PaintScaleUniform -{ - HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - auto *out = c->serializer->embed (this); - if (unlikely (!out)) return_trace (false); - - return_trace (out->src.serialize_subset (c, src, this)); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && src.sanitize (c, this)); - } - - HBUINT8 format; /* format = 20 (noVar) or 21(Var) */ - Offset24To src; /* Offset (from beginning of PaintScaleUniform table) to Paint subtable. */ - F2DOT14 scale; - public: - DEFINE_SIZE_STATIC (4 + F2DOT14::static_size); -}; - -struct PaintScaleUniformAroundCenter -{ - HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - auto *out = c->serializer->embed (this); - if (unlikely (!out)) return_trace (false); - - return_trace (out->src.serialize_subset (c, src, this)); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && src.sanitize (c, this)); - } - - HBUINT8 format; /* format = 22 (noVar) or 23(Var) */ - Offset24To src; /* Offset (from beginning of PaintScaleUniformAroundCenter table) to Paint subtable. */ - F2DOT14 scale; - FWORD centerX; - FWORD centerY; - public: - DEFINE_SIZE_STATIC (4 + F2DOT14::static_size + 2 * FWORD::static_size); -}; - -struct PaintRotate -{ - HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - auto *out = c->serializer->embed (this); - if (unlikely (!out)) return_trace (false); - - return_trace (out->src.serialize_subset (c, src, this)); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && src.sanitize (c, this)); - } - - HBUINT8 format; /* format = 24 (noVar) or 25(Var) */ - Offset24To src; /* Offset (from beginning of PaintRotate table) to Paint subtable. */ - F2DOT14 angle; - public: - DEFINE_SIZE_STATIC (4 + F2DOT14::static_size); -}; - -struct PaintRotateAroundCenter -{ - HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - auto *out = c->serializer->embed (this); - if (unlikely (!out)) return_trace (false); - - return_trace (out->src.serialize_subset (c, src, this)); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && src.sanitize (c, this)); - } - - HBUINT8 format; /* format = 26 (noVar) or 27(Var) */ - Offset24To src; /* Offset (from beginning of PaintRotateAroundCenter table) to Paint subtable. */ - F2DOT14 angle; - FWORD centerX; - FWORD centerY; - public: - DEFINE_SIZE_STATIC (4 + F2DOT14::static_size + 2 * FWORD::static_size); -}; - -struct PaintSkew -{ - HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - auto *out = c->serializer->embed (this); - if (unlikely (!out)) return_trace (false); - - return_trace (out->src.serialize_subset (c, src, this)); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && src.sanitize (c, this)); - } - - HBUINT8 format; /* format = 28(noVar) or 29 (Var) */ - Offset24To src; /* Offset (from beginning of PaintSkew table) to Paint subtable. */ - F2DOT14 xSkewAngle; - F2DOT14 ySkewAngle; - public: - DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size); -}; - -struct PaintSkewAroundCenter -{ - HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - auto *out = c->serializer->embed (this); - if (unlikely (!out)) return_trace (false); - - return_trace (out->src.serialize_subset (c, src, this)); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && src.sanitize (c, this)); - } - - HBUINT8 format; /* format = 30(noVar) or 31 (Var) */ - Offset24To src; /* Offset (from beginning of PaintSkewAroundCenter table) to Paint subtable. */ - F2DOT14 xSkewAngle; - F2DOT14 ySkewAngle; - FWORD centerX; - FWORD centerY; - public: - DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size + 2 * FWORD::static_size); -}; - -struct PaintComposite -{ - void closurev1 (hb_colrv1_closure_context_t* c) const; - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - auto *out = c->serializer->embed (this); - if (unlikely (!out)) return_trace (false); - - if (!out->src.serialize_subset (c, src, this)) return_trace (false); - return_trace (out->backdrop.serialize_subset (c, backdrop, this)); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - src.sanitize (c, this) && - backdrop.sanitize (c, this)); - } - - HBUINT8 format; /* format = 32 */ - Offset24To src; /* Offset (from beginning of PaintComposite table) to source Paint subtable. */ - CompositeMode mode; /* If mode is unrecognized use COMPOSITE_CLEAR */ - Offset24To backdrop; /* Offset (from beginning of PaintComposite table) to backdrop Paint subtable. */ - public: - DEFINE_SIZE_STATIC (8); -}; - -struct ClipBoxFormat1 -{ - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this)); - } - - public: - HBUINT8 format; /* format = 1(noVar) or 2(Var)*/ - FWORD xMin; - FWORD yMin; - FWORD xMax; - FWORD yMax; - public: - DEFINE_SIZE_STATIC (1 + 4 * FWORD::static_size); -}; - -struct ClipBoxFormat2 : Variable {}; - -struct ClipBox -{ - ClipBox* copy (hb_serialize_context_t *c) const - { - TRACE_SERIALIZE (this); - switch (u.format) { - case 1: return_trace (reinterpret_cast (c->embed (u.format1))); - case 2: return_trace (reinterpret_cast (c->embed (u.format2))); - default:return_trace (nullptr); - } - } - - template - typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const - { - TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); - switch (u.format) { - case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); - case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); - default:return_trace (c->default_return_value ()); - } - } - - protected: - union { - HBUINT8 format; /* Format identifier */ - ClipBoxFormat1 format1; - ClipBoxFormat2 format2; - } u; -}; - -struct ClipRecord -{ - ClipRecord* copy (hb_serialize_context_t *c, const void *base) const - { - TRACE_SERIALIZE (this); - auto *out = c->embed (this); - if (unlikely (!out)) return_trace (nullptr); - if (!out->clipBox.serialize_copy (c, clipBox, base)) return_trace (nullptr); - return_trace (out); - } - - bool sanitize (hb_sanitize_context_t *c, const void *base) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && clipBox.sanitize (c, base)); - } - - public: - HBUINT16 startGlyphID; // first gid clip applies to - HBUINT16 endGlyphID; // last gid clip applies to, inclusive - Offset24To clipBox; // Box or VarBox - public: - DEFINE_SIZE_STATIC (7); -}; - -struct ClipList -{ - unsigned serialize_clip_records (hb_serialize_context_t *c, - const hb_set_t& gids, - const hb_map_t& gid_offset_map) const - { - TRACE_SERIALIZE (this); - if (gids.is_empty () || - gid_offset_map.get_population () != gids.get_population ()) - return_trace (0); - - unsigned count = 0; - - hb_codepoint_t start_gid= gids.get_min (); - hb_codepoint_t prev_gid = start_gid; - - unsigned offset = gid_offset_map.get (start_gid); - unsigned prev_offset = offset; - for (const hb_codepoint_t _ : gids.iter ()) - { - if (_ == start_gid) continue; - - offset = gid_offset_map.get (_); - if (_ == prev_gid + 1 && offset == prev_offset) - { - prev_gid = _; - continue; - } - - ClipRecord record; - record.startGlyphID = start_gid; - record.endGlyphID = prev_gid; - record.clipBox = prev_offset; - - if (!c->copy (record, this)) return_trace (0); - count++; - - start_gid = _; - prev_gid = _; - prev_offset = offset; - } - - //last one - { - ClipRecord record; - record.startGlyphID = start_gid; - record.endGlyphID = prev_gid; - record.clipBox = prev_offset; - if (!c->copy (record, this)) return_trace (0); - count++; - } - return_trace (count); - } - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - auto *out = c->serializer->start_embed (*this); - if (unlikely (!c->serializer->extend_min (out))) return_trace (false); - if (!c->serializer->check_assign (out->format, format, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false); - - const hb_set_t& glyphset = *c->plan->_glyphset_colred; - const hb_map_t &glyph_map = *c->plan->glyph_map; - - hb_map_t new_gid_offset_map; - hb_set_t new_gids; - for (const ClipRecord& record : clips.iter ()) - { - unsigned start_gid = record.startGlyphID; - unsigned end_gid = record.endGlyphID; - for (unsigned gid = start_gid; gid <= end_gid; gid++) - { - if (!glyphset.has (gid) || !glyph_map.has (gid)) continue; - unsigned new_gid = glyph_map.get (gid); - new_gid_offset_map.set (new_gid, record.clipBox); - new_gids.add (new_gid); - } - } - - unsigned count = serialize_clip_records (c->serializer, new_gids, new_gid_offset_map); - if (!count) return_trace (false); - return_trace (c->serializer->check_assign (out->clips.len, count, HB_SERIALIZE_ERROR_INT_OVERFLOW)); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && clips.sanitize (c, this)); - } - - HBUINT8 format; // Set to 1. - Array32Of clips; // Clip records, sorted by startGlyphID - public: - DEFINE_SIZE_ARRAY_SIZED (5, clips); -}; - -struct Paint -{ - - template - bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const - { - TRACE_SANITIZE (this); - - if (unlikely (!c->check_start_recursion (HB_COLRV1_MAX_NESTING_LEVEL))) - return_trace (c->no_dispatch_return_value ()); - - return_trace (c->end_recursion (this->dispatch (c, std::forward (ds)...))); - } - - template - typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const - { - TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); - switch (u.format) { - case 1: return_trace (c->dispatch (u.paintformat1, std::forward (ds)...)); - case 2: return_trace (c->dispatch (u.paintformat2, std::forward (ds)...)); - case 3: return_trace (c->dispatch (u.paintformat3, std::forward (ds)...)); - case 4: return_trace (c->dispatch (u.paintformat4, std::forward (ds)...)); - case 5: return_trace (c->dispatch (u.paintformat5, std::forward (ds)...)); - case 6: return_trace (c->dispatch (u.paintformat6, std::forward (ds)...)); - case 7: return_trace (c->dispatch (u.paintformat7, std::forward (ds)...)); - case 8: return_trace (c->dispatch (u.paintformat8, std::forward (ds)...)); - case 9: return_trace (c->dispatch (u.paintformat9, std::forward (ds)...)); - case 10: return_trace (c->dispatch (u.paintformat10, std::forward (ds)...)); - case 11: return_trace (c->dispatch (u.paintformat11, std::forward (ds)...)); - case 12: return_trace (c->dispatch (u.paintformat12, std::forward (ds)...)); - case 13: return_trace (c->dispatch (u.paintformat13, std::forward (ds)...)); - case 14: return_trace (c->dispatch (u.paintformat14, std::forward (ds)...)); - case 15: return_trace (c->dispatch (u.paintformat15, std::forward (ds)...)); - case 16: return_trace (c->dispatch (u.paintformat16, std::forward (ds)...)); - case 17: return_trace (c->dispatch (u.paintformat17, std::forward (ds)...)); - case 18: return_trace (c->dispatch (u.paintformat18, std::forward (ds)...)); - case 19: return_trace (c->dispatch (u.paintformat19, std::forward (ds)...)); - case 20: return_trace (c->dispatch (u.paintformat20, std::forward (ds)...)); - case 21: return_trace (c->dispatch (u.paintformat21, std::forward (ds)...)); - case 22: return_trace (c->dispatch (u.paintformat22, std::forward (ds)...)); - case 23: return_trace (c->dispatch (u.paintformat23, std::forward (ds)...)); - case 24: return_trace (c->dispatch (u.paintformat24, std::forward (ds)...)); - case 25: return_trace (c->dispatch (u.paintformat25, std::forward (ds)...)); - case 26: return_trace (c->dispatch (u.paintformat26, std::forward (ds)...)); - case 27: return_trace (c->dispatch (u.paintformat27, std::forward (ds)...)); - case 28: return_trace (c->dispatch (u.paintformat28, std::forward (ds)...)); - case 29: return_trace (c->dispatch (u.paintformat29, std::forward (ds)...)); - case 30: return_trace (c->dispatch (u.paintformat30, std::forward (ds)...)); - case 31: return_trace (c->dispatch (u.paintformat31, std::forward (ds)...)); - case 32: return_trace (c->dispatch (u.paintformat32, std::forward (ds)...)); - default:return_trace (c->default_return_value ()); - } - } - - protected: - union { - HBUINT8 format; - PaintColrLayers paintformat1; - PaintSolid paintformat2; - Variable paintformat3; - PaintLinearGradient paintformat4; - Variable> paintformat5; - PaintRadialGradient paintformat6; - Variable> paintformat7; - PaintSweepGradient paintformat8; - Variable> paintformat9; - PaintGlyph paintformat10; - PaintColrGlyph paintformat11; - PaintTransform paintformat12; - PaintTransform paintformat13; - PaintTranslate paintformat14; - Variable paintformat15; - PaintScale paintformat16; - Variable paintformat17; - PaintScaleAroundCenter paintformat18; - Variable paintformat19; - PaintScaleUniform paintformat20; - Variable paintformat21; - PaintScaleUniformAroundCenter paintformat22; - Variable paintformat23; - PaintRotate paintformat24; - Variable paintformat25; - PaintRotateAroundCenter paintformat26; - Variable paintformat27; - PaintSkew paintformat28; - Variable paintformat29; - PaintSkewAroundCenter paintformat30; - Variable paintformat31; - PaintComposite paintformat32; - } u; - public: - DEFINE_SIZE_MIN (2); -}; - -struct BaseGlyphPaintRecord -{ - int cmp (hb_codepoint_t g) const - { return g < glyphId ? -1 : g > glyphId ? 1 : 0; } - - bool serialize (hb_serialize_context_t *s, const hb_map_t* glyph_map, - const void* src_base, hb_subset_context_t *c) const - { - TRACE_SERIALIZE (this); - auto *out = s->embed (this); - if (unlikely (!out)) return_trace (false); - if (!s->check_assign (out->glyphId, glyph_map->get (glyphId), - HB_SERIALIZE_ERROR_INT_OVERFLOW)) - return_trace (false); - - return_trace (out->paint.serialize_subset (c, paint, src_base)); - } - - bool sanitize (hb_sanitize_context_t *c, const void *base) const - { - TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this) && paint.sanitize (c, base))); - } - - public: - HBGlyphID16 glyphId; /* Glyph ID of reference glyph */ - Offset32To paint; /* Offset (from beginning of BaseGlyphPaintRecord array) to Paint, - * Typically PaintColrLayers */ - public: - DEFINE_SIZE_STATIC (6); -}; - -struct BaseGlyphList : SortedArray32Of -{ - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - auto *out = c->serializer->start_embed (this); - if (unlikely (!c->serializer->extend_min (out))) return_trace (false); - const hb_set_t* glyphset = c->plan->_glyphset_colred; - - for (const auto& _ : as_array ()) - { - unsigned gid = _.glyphId; - if (!glyphset->has (gid)) continue; - - if (_.serialize (c->serializer, c->plan->glyph_map, this, c)) out->len++; - else return_trace (false); - } - - return_trace (out->len != 0); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (SortedArray32Of::sanitize (c, this)); - } -}; - -struct LayerList : Array32OfOffset32To -{ - const Paint& get_paint (unsigned i) const - { return this+(*this)[i]; } - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - auto *out = c->serializer->start_embed (this); - if (unlikely (!c->serializer->extend_min (out))) return_trace (false); - - for (const auto& _ : + hb_enumerate (*this) - | hb_filter (c->plan->colrv1_layers, hb_first)) - - { - auto *o = out->serialize_append (c->serializer); - if (unlikely (!o) || !o->serialize_subset (c, _.second, this)) - return_trace (false); - } - return_trace (true); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (Array32OfOffset32To::sanitize (c, this)); - } -}; - -struct COLR -{ - static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR; - - bool has_data () const { return numBaseGlyphs; } - - unsigned int get_glyph_layers (hb_codepoint_t glyph, - unsigned int start_offset, - unsigned int *count, /* IN/OUT. May be NULL. */ - hb_ot_color_layer_t *layers /* OUT. May be NULL. */) const - { - const BaseGlyphRecord &record = (this+baseGlyphsZ).bsearch (numBaseGlyphs, glyph); - - hb_array_t all_layers = (this+layersZ).as_array (numLayers); - hb_array_t glyph_layers = all_layers.sub_array (record.firstLayerIdx, - record.numLayers); - if (count) - { - + glyph_layers.sub_array (start_offset, count) - | hb_sink (hb_array (layers, *count)) - ; - } - return glyph_layers.length; - } - - struct accelerator_t - { - accelerator_t (hb_face_t *face) - { colr = hb_sanitize_context_t ().reference_table (face); } - ~accelerator_t () { this->colr.destroy (); } - - bool is_valid () { return colr.get_blob ()->length; } - - void closure_glyphs (hb_codepoint_t glyph, - hb_set_t *related_ids /* OUT */) const - { colr->closure_glyphs (glyph, related_ids); } - - void closure_V0palette_indices (const hb_set_t *glyphs, - hb_set_t *palettes /* OUT */) const - { colr->closure_V0palette_indices (glyphs, palettes); } - - void closure_forV1 (hb_set_t *glyphset, - hb_set_t *layer_indices, - hb_set_t *palette_indices) const - { colr->closure_forV1 (glyphset, layer_indices, palette_indices); } - - private: - hb_blob_ptr_t colr; - }; - - void closure_glyphs (hb_codepoint_t glyph, - hb_set_t *related_ids /* OUT */) const - { - const BaseGlyphRecord *record = get_base_glyph_record (glyph); - if (!record) return; - - auto glyph_layers = (this+layersZ).as_array (numLayers).sub_array (record->firstLayerIdx, - record->numLayers); - if (!glyph_layers.length) return; - related_ids->add_array (&glyph_layers[0].glyphId, glyph_layers.length, LayerRecord::min_size); - } - - void closure_V0palette_indices (const hb_set_t *glyphs, - hb_set_t *palettes /* OUT */) const - { - if (!numBaseGlyphs || !numLayers) return; - hb_array_t baseGlyphs = (this+baseGlyphsZ).as_array (numBaseGlyphs); - hb_array_t all_layers = (this+layersZ).as_array (numLayers); - - for (const BaseGlyphRecord record : baseGlyphs) - { - if (!glyphs->has (record.glyphId)) continue; - hb_array_t glyph_layers = all_layers.sub_array (record.firstLayerIdx, - record.numLayers); - for (const LayerRecord layer : glyph_layers) - palettes->add (layer.colorIdx); - } - } - - void closure_forV1 (hb_set_t *glyphset, - hb_set_t *layer_indices, - hb_set_t *palette_indices) const - { - if (version != 1) return; - hb_set_t visited_glyphs; - - hb_colrv1_closure_context_t c (this, &visited_glyphs, layer_indices, palette_indices); - const BaseGlyphList &baseglyph_paintrecords = this+baseGlyphList; - - for (const BaseGlyphPaintRecord &baseglyph_paintrecord: baseglyph_paintrecords.iter ()) - { - unsigned gid = baseglyph_paintrecord.glyphId; - if (!glyphset->has (gid)) continue; - - const Paint &paint = &baseglyph_paintrecords+baseglyph_paintrecord.paint; - paint.dispatch (&c); - } - hb_set_union (glyphset, &visited_glyphs); - } - - const LayerList& get_layerList () const - { return (this+layerList); } - - const BaseGlyphList& get_baseglyphList () const - { return (this+baseGlyphList); } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - (this+baseGlyphsZ).sanitize (c, numBaseGlyphs) && - (this+layersZ).sanitize (c, numLayers) && - (version == 0 || - (COLRV1_ENABLE_SUBSETTING && version == 1 && - baseGlyphList.sanitize (c, this) && - layerList.sanitize (c, this) && - clipList.sanitize (c, this) && - varIdxMap.sanitize (c, this) && - varStore.sanitize (c, this)))); - } - - template - bool serialize_V0 (hb_serialize_context_t *c, - unsigned version, - BaseIterator base_it, - LayerIterator layer_it) - { - TRACE_SERIALIZE (this); - if (unlikely (base_it.len () != layer_it.len ())) - return_trace (false); - - this->version = version; - numLayers = 0; - numBaseGlyphs = base_it.len (); - if (numBaseGlyphs == 0) - { - baseGlyphsZ = 0; - layersZ = 0; - return_trace (true); - } - - c->push (); - for (const hb_item_type _ : + base_it.iter ()) - { - auto* record = c->embed (_); - if (unlikely (!record)) return_trace (false); - record->firstLayerIdx = numLayers; - numLayers += record->numLayers; - } - c->add_link (baseGlyphsZ, c->pop_pack ()); - - c->push (); - for (const hb_item_type& _ : + layer_it.iter ()) - _.as_array ().copy (c); - - c->add_link (layersZ, c->pop_pack ()); - - return_trace (true); - } - - const BaseGlyphRecord* get_base_glyph_record (hb_codepoint_t gid) const - { - const BaseGlyphRecord* record = &(this+baseGlyphsZ).bsearch (numBaseGlyphs, (unsigned int) gid); - if (record == &Null (BaseGlyphRecord) || - (record && (hb_codepoint_t) record->glyphId != gid)) - record = nullptr; - return record; - } - - const BaseGlyphPaintRecord* get_base_glyph_paintrecord (hb_codepoint_t gid) const - { - const BaseGlyphPaintRecord* record = &(this+baseGlyphList).bsearch ((unsigned) gid); - if ((record && (hb_codepoint_t) record->glyphId != gid)) - record = nullptr; - return record; - } - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - - const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map; - const hb_set_t& glyphset = *c->plan->_glyphset_colred; - - auto base_it = - + hb_range (c->plan->num_output_glyphs ()) - | hb_filter ([&](hb_codepoint_t new_gid) - { - hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid); - if (glyphset.has (old_gid)) return true; - return false; - }) - | hb_map_retains_sorting ([&](hb_codepoint_t new_gid) - { - hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid); - - const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid); - if (unlikely (!old_record)) - return hb_pair_t (false, Null (BaseGlyphRecord)); - BaseGlyphRecord new_record = {}; - new_record.glyphId = new_gid; - new_record.numLayers = old_record->numLayers; - return hb_pair_t (true, new_record); - }) - | hb_filter (hb_first) - | hb_map_retains_sorting (hb_second) - ; - - auto layer_it = - + hb_range (c->plan->num_output_glyphs ()) - | hb_map (reverse_glyph_map) - | hb_filter (glyphset) - | hb_map_retains_sorting ([&](hb_codepoint_t old_gid) - { - const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid); - hb_vector_t out_layers; - - if (unlikely (!old_record || - old_record->firstLayerIdx >= numLayers || - old_record->firstLayerIdx + old_record->numLayers > numLayers)) - return hb_pair_t> (false, out_layers); - - auto layers = (this+layersZ).as_array (numLayers).sub_array (old_record->firstLayerIdx, - old_record->numLayers); - out_layers.resize (layers.length); - for (unsigned int i = 0; i < layers.length; i++) { - out_layers[i] = layers[i]; - hb_codepoint_t new_gid = 0; - if (unlikely (!c->plan->new_gid_for_old_gid (out_layers[i].glyphId, &new_gid))) - return hb_pair_t> (false, out_layers); - out_layers[i].glyphId = new_gid; - out_layers[i].colorIdx = c->plan->colr_palettes->get (layers[i].colorIdx); - } - - return hb_pair_t> (true, out_layers); - }) - | hb_filter (hb_first) - | hb_map_retains_sorting (hb_second) - ; - - if (version == 0 && (!base_it || !layer_it)) - return_trace (false); - - COLR *colr_prime = c->serializer->start_embed (); - if (unlikely (!c->serializer->extend_min (colr_prime))) return_trace (false); - - if (version == 0) - return_trace (colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it)); - - auto snap = c->serializer->snapshot (); - if (!c->serializer->allocate_size (5 * HBUINT32::static_size)) return_trace (false); - if (!colr_prime->baseGlyphList.serialize_subset (c, baseGlyphList, this)) - { - if (c->serializer->in_error ()) return_trace (false); - //no more COLRv1 glyphs: downgrade to version 0 - c->serializer->revert (snap); - return_trace (colr_prime->serialize_V0 (c->serializer, 0, base_it, layer_it)); - } - - if (!colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it)) return_trace (false); - - colr_prime->layerList.serialize_subset (c, layerList, this); - colr_prime->clipList.serialize_subset (c, clipList, this); - colr_prime->varIdxMap.serialize_copy (c->serializer, varIdxMap, this); - //TODO: subset varStore once it's implemented in fonttools - return_trace (true); - } - - protected: - HBUINT16 version; /* Table version number (starts at 0). */ - HBUINT16 numBaseGlyphs; /* Number of Base Glyph Records. */ - NNOffset32To> - baseGlyphsZ; /* Offset to Base Glyph records. */ - NNOffset32To> - layersZ; /* Offset to Layer Records. */ - HBUINT16 numLayers; /* Number of Layer Records. */ - // Version-1 additions - Offset32To baseGlyphList; - Offset32To layerList; - Offset32To clipList; // Offset to ClipList table (may be NULL) - Offset32To varIdxMap; // Offset to DeltaSetIndexMap table (may be NULL) - Offset32To varStore; - public: - DEFINE_SIZE_MIN (14); -}; - -struct COLR_accelerator_t : COLR::accelerator_t { - COLR_accelerator_t (hb_face_t *face) : COLR::accelerator_t (face) {} -}; - -} /* namespace OT */ - - -#endif /* HB_OT_COLOR_COLR_TABLE_HH */ diff --git a/libs/harfbuzz/src/hb-ot-color.cc b/libs/harfbuzz/src/hb-ot-color.cc index 696ca3e17..37d42e08d 100644 --- a/libs/harfbuzz/src/hb-ot-color.cc +++ b/libs/harfbuzz/src/hb-ot-color.cc @@ -31,11 +31,11 @@ #include "hb-ot.h" -#include "hb-ot-color-cbdt-table.hh" -#include "hb-ot-color-colr-table.hh" -#include "hb-ot-color-cpal-table.hh" -#include "hb-ot-color-sbix-table.hh" -#include "hb-ot-color-svg-table.hh" +#include "OT/Color/CBDT/CBDT.hh" +#include "OT/Color/COLR/COLR.hh" +#include "OT/Color/CPAL/CPAL.hh" +#include "OT/Color/sbix/sbix.hh" +#include "OT/Color/svg/svg.hh" /** @@ -167,6 +167,10 @@ hb_ot_color_palette_get_flags (hb_face_t *face, * for allocating a buffer of suitable size before calling * hb_ot_color_palette_get_colors() a second time. * + * The RGBA values in the palette are unpremultiplied. See the + * OpenType spec [CPAL](https://learn.microsoft.com/en-us/typography/opentype/spec/cpal) + * section for details. + * * Return value: the total number of colors in the palette * * Since: 2.1.0 @@ -190,7 +194,8 @@ hb_ot_color_palette_get_colors (hb_face_t *face, * hb_ot_color_has_layers: * @face: #hb_face_t to work upon * - * Tests whether a face includes any `COLR` color layers. + * Tests whether a face includes a `COLR` table + * with data according to COLRv0. * * Return value: `true` if data found, `false` otherwise * @@ -199,7 +204,43 @@ hb_ot_color_palette_get_colors (hb_face_t *face, hb_bool_t hb_ot_color_has_layers (hb_face_t *face) { - return face->table.COLR->has_data (); + return face->table.COLR->has_v0_data (); +} + +/** + * hb_ot_color_has_paint: + * @face: #hb_face_t to work upon + * + * Tests where a face includes a `COLR` table + * with data according to COLRv1. + * + * Return value: `true` if data found, `false` otherwise + * + * Since: 7.0.0 + */ +hb_bool_t +hb_ot_color_has_paint (hb_face_t *face) +{ + return face->table.COLR->has_v1_data (); +} + +/** + * hb_ot_color_glyph_has_paint: + * @face: #hb_face_t to work upon + * @glyph: The glyph index to query + * + * Tests where a face includes COLRv1 paint + * data for @glyph. + * + * Return value: `true` if data found, `false` otherwise + * + * Since: 7.0.0 + */ +hb_bool_t +hb_ot_color_glyph_has_paint (hb_face_t *face, + hb_codepoint_t glyph) +{ + return face->table.COLR->has_paint_for_glyph (glyph); } /** diff --git a/libs/harfbuzz/src/hb-ot-color.h b/libs/harfbuzz/src/hb-ot-color.h index d11e07e23..22ee497e3 100644 --- a/libs/harfbuzz/src/hb-ot-color.h +++ b/libs/harfbuzz/src/hb-ot-color.h @@ -120,6 +120,15 @@ hb_ot_color_glyph_get_layers (hb_face_t *face, unsigned int *layer_count, /* IN/OUT. May be NULL. */ hb_ot_color_layer_t *layers /* OUT. May be NULL. */); +/* COLRv1 */ + +HB_EXTERN hb_bool_t +hb_ot_color_has_paint (hb_face_t *face); + +HB_EXTERN hb_bool_t +hb_ot_color_glyph_has_paint (hb_face_t *face, + hb_codepoint_t glyph); + /* * SVG */ diff --git a/libs/harfbuzz/src/hb-ot-deprecated.h b/libs/harfbuzz/src/hb-ot-deprecated.h index 5192ff73e..60672ab12 100644 --- a/libs/harfbuzz/src/hb-ot-deprecated.h +++ b/libs/harfbuzz/src/hb-ot-deprecated.h @@ -67,26 +67,30 @@ HB_BEGIN_DECLS /* Like hb_ot_layout_table_find_script, but takes zero-terminated array of scripts to test */ -HB_EXTERN HB_DEPRECATED_FOR (hb_ot_layout_table_select_script) hb_bool_t +HB_DEPRECATED_FOR (hb_ot_layout_table_select_script) +HB_EXTERN hb_bool_t hb_ot_layout_table_choose_script (hb_face_t *face, hb_tag_t table_tag, const hb_tag_t *script_tags, unsigned int *script_index, hb_tag_t *chosen_script); -HB_EXTERN HB_DEPRECATED_FOR (hb_ot_layout_script_select_language) hb_bool_t +HB_DEPRECATED_FOR (hb_ot_layout_script_select_language) +HB_EXTERN hb_bool_t hb_ot_layout_script_find_language (hb_face_t *face, hb_tag_t table_tag, unsigned int script_index, hb_tag_t language_tag, unsigned int *language_index); -HB_EXTERN HB_DEPRECATED_FOR (hb_ot_tags_from_script_and_language) void +HB_DEPRECATED_FOR (hb_ot_tags_from_script_and_language) +HB_EXTERN void hb_ot_tags_from_script (hb_script_t script, hb_tag_t *script_tag_1, hb_tag_t *script_tag_2); -HB_EXTERN HB_DEPRECATED_FOR (hb_ot_tags_from_script_and_language) hb_tag_t +HB_DEPRECATED_FOR (hb_ot_tags_from_script_and_language) +HB_EXTERN hb_tag_t hb_ot_tag_from_language (hb_language_t language); @@ -121,13 +125,15 @@ typedef struct hb_ot_var_axis_t { float max_value; } hb_ot_var_axis_t; -HB_EXTERN HB_DEPRECATED_FOR (hb_ot_var_get_axis_infos) unsigned int +HB_DEPRECATED_FOR (hb_ot_var_get_axis_infos) +HB_EXTERN unsigned int hb_ot_var_get_axes (hb_face_t *face, unsigned int start_offset, unsigned int *axes_count /* IN/OUT */, hb_ot_var_axis_t *axes_array /* OUT */); -HB_EXTERN HB_DEPRECATED_FOR (hb_ot_var_find_axis_info) hb_bool_t +HB_DEPRECATED_FOR (hb_ot_var_find_axis_info) +HB_EXTERN hb_bool_t hb_ot_var_find_axis (hb_face_t *face, hb_tag_t axis_tag, unsigned int *axis_index, diff --git a/libs/harfbuzz/src/hb-ot-face-table-list.hh b/libs/harfbuzz/src/hb-ot-face-table-list.hh index c05034b3b..dd4befffa 100644 --- a/libs/harfbuzz/src/hb-ot-face-table-list.hh +++ b/libs/harfbuzz/src/hb-ot-face-table-list.hh @@ -56,9 +56,9 @@ HB_OT_CORE_TABLE (OT, maxp) #if !defined(HB_NO_FACE_COLLECT_UNICODES) || !defined(HB_NO_OT_FONT) HB_OT_ACCELERATOR (OT, cmap) #endif -HB_OT_TABLE (OT, hhea) +HB_OT_CORE_TABLE (OT, hhea) HB_OT_ACCELERATOR (OT, hmtx) -HB_OT_TABLE (OT, OS2) +HB_OT_CORE_TABLE (OT, OS2) #if !defined(HB_NO_OT_FONT_GLYPH_NAMES) || !defined(HB_NO_METRICS) || !defined(HB_NO_STYLE) HB_OT_ACCELERATOR (OT, post) #endif @@ -66,7 +66,7 @@ HB_OT_ACCELERATOR (OT, post) HB_OT_ACCELERATOR (OT, name) #endif #ifndef HB_NO_STYLE -HB_OT_TABLE (OT, STAT) +HB_OT_CORE_TABLE (OT, STAT) #endif #ifndef HB_NO_META HB_OT_ACCELERATOR (OT, meta) @@ -74,9 +74,9 @@ HB_OT_ACCELERATOR (OT, meta) /* Vertical layout. */ #ifndef HB_NO_VERTICAL -HB_OT_TABLE (OT, vhea) +HB_OT_CORE_TABLE (OT, vhea) HB_OT_ACCELERATOR (OT, vmtx) -HB_OT_TABLE (OT, VORG) +HB_OT_CORE_TABLE (OT, VORG) #endif /* TrueType outlines. */ @@ -91,15 +91,19 @@ HB_OT_ACCELERATOR (OT, cff2) /* OpenType variations. */ #ifndef HB_NO_VAR -HB_OT_TABLE (OT, fvar) -HB_OT_TABLE (OT, avar) +HB_OT_CORE_TABLE (OT, fvar) +HB_OT_CORE_TABLE (OT, avar) +HB_OT_CORE_TABLE (OT, cvar) HB_OT_ACCELERATOR (OT, gvar) -HB_OT_TABLE (OT, MVAR) +HB_OT_CORE_TABLE (OT, MVAR) +#ifndef HB_NO_VAR_COMPOSITES +HB_OT_CORE_TABLE (OT, VARC) +#endif #endif /* Legacy kern. */ #ifndef HB_NO_OT_KERN -HB_OT_TABLE (OT, kern) +HB_OT_ACCELERATOR (OT, kern) #endif /* OpenType shaping. */ @@ -107,19 +111,19 @@ HB_OT_TABLE (OT, kern) HB_OT_ACCELERATOR (OT, GDEF) HB_OT_ACCELERATOR (OT, GSUB) HB_OT_ACCELERATOR (OT, GPOS) -//HB_OT_TABLE (OT, JSTF) +//HB_OT_CORE_TABLE (OT, JSTF) #endif /* OpenType baseline. */ #ifndef HB_NO_BASE -HB_OT_TABLE (OT, BASE) +HB_OT_CORE_TABLE (OT, BASE) #endif /* AAT shaping. */ #ifndef HB_NO_AAT -HB_OT_TABLE (AAT, morx) -HB_OT_TABLE (AAT, mort) -HB_OT_TABLE (AAT, kerx) +HB_OT_ACCELERATOR (AAT, morx) +HB_OT_ACCELERATOR (AAT, mort) +HB_OT_ACCELERATOR (AAT, kerx) HB_OT_TABLE (AAT, ankr) HB_OT_TABLE (AAT, trak) HB_OT_TABLE (AAT, ltag) @@ -129,8 +133,8 @@ HB_OT_TABLE (AAT, feat) /* OpenType color fonts. */ #ifndef HB_NO_COLOR -HB_OT_TABLE (OT, COLR) -HB_OT_TABLE (OT, CPAL) +HB_OT_CORE_TABLE (OT, COLR) +HB_OT_CORE_TABLE (OT, CPAL) HB_OT_ACCELERATOR (OT, CBDT) HB_OT_ACCELERATOR (OT, sbix) HB_OT_ACCELERATOR (OT, SVG) @@ -138,7 +142,7 @@ HB_OT_ACCELERATOR (OT, SVG) /* OpenType math. */ #ifndef HB_NO_MATH -HB_OT_TABLE (OT, MATH) +HB_OT_CORE_TABLE (OT, MATH) #endif diff --git a/libs/harfbuzz/src/hb-ot-face.cc b/libs/harfbuzz/src/hb-ot-face.cc index 5ef8df43c..b0c927979 100644 --- a/libs/harfbuzz/src/hb-ot-face.cc +++ b/libs/harfbuzz/src/hb-ot-face.cc @@ -35,12 +35,14 @@ #include "hb-ot-meta-table.hh" #include "hb-ot-name-table.hh" #include "hb-ot-post-table.hh" -#include "hb-ot-color-cbdt-table.hh" -#include "hb-ot-color-sbix-table.hh" -#include "hb-ot-color-svg-table.hh" +#include "OT/Color/CBDT/CBDT.hh" +#include "OT/Color/sbix/sbix.hh" +#include "OT/Color/svg/svg.hh" #include "hb-ot-layout-gdef-table.hh" #include "hb-ot-layout-gsub-table.hh" #include "hb-ot-layout-gpos-table.hh" +#include "hb-aat-layout-kerx-table.hh" +#include "hb-aat-layout-morx-table.hh" void hb_ot_face_t::init0 (hb_face_t *face) diff --git a/libs/harfbuzz/src/hb-ot-font.cc b/libs/harfbuzz/src/hb-ot-font.cc index 825b30853..7b4724710 100644 --- a/libs/harfbuzz/src/hb-ot-font.cc +++ b/libs/harfbuzz/src/hb-ot-font.cc @@ -34,17 +34,21 @@ #include "hb-font.hh" #include "hb-machinery.hh" #include "hb-ot-face.hh" +#include "hb-outline.hh" #include "hb-ot-cmap-table.hh" #include "hb-ot-glyf-table.hh" -#include "hb-ot-cff1-table.hh" #include "hb-ot-cff2-table.hh" +#include "hb-ot-cff1-table.hh" #include "hb-ot-hmtx-table.hh" #include "hb-ot-post-table.hh" #include "hb-ot-stat-table.hh" // Just so we compile it; unused otherwise. +#include "hb-ot-var-varc-table.hh" #include "hb-ot-vorg-table.hh" -#include "hb-ot-color-cbdt-table.hh" -#include "hb-ot-color-sbix-table.hh" +#include "OT/Color/CBDT/CBDT.hh" +#include "OT/Color/COLR/COLR.hh" +#include "OT/Color/sbix/sbix.hh" +#include "OT/Color/svg/svg.hh" /** @@ -58,12 +62,21 @@ * never need to call these functions directly. **/ +using hb_ot_font_cmap_cache_t = hb_cache_t<21, 16, 8, true>; using hb_ot_font_advance_cache_t = hb_cache_t<24, 16, 8, true>; +#ifndef HB_NO_OT_FONT_CMAP_CACHE +static hb_user_data_key_t hb_ot_font_cmap_cache_user_data_key; +#endif + struct hb_ot_font_t { const hb_ot_face_t *ot_face; +#ifndef HB_NO_OT_FONT_CMAP_CACHE + hb_ot_font_cmap_cache_t *cmap_cache; +#endif + /* h_advance caching */ mutable hb_atomic_int_t cached_coords_serial; mutable hb_atomic_ptr_t advance_cache; @@ -78,6 +91,35 @@ _hb_ot_font_create (hb_font_t *font) ot_font->ot_face = &font->face->table; +#ifndef HB_NO_OT_FONT_CMAP_CACHE + // retry: + auto *cmap_cache = (hb_ot_font_cmap_cache_t *) hb_face_get_user_data (font->face, + &hb_ot_font_cmap_cache_user_data_key); + if (!cmap_cache) + { + cmap_cache = (hb_ot_font_cmap_cache_t *) hb_malloc (sizeof (hb_ot_font_cmap_cache_t)); + if (unlikely (!cmap_cache)) goto out; + new (cmap_cache) hb_ot_font_cmap_cache_t (); + if (unlikely (!hb_face_set_user_data (font->face, + &hb_ot_font_cmap_cache_user_data_key, + cmap_cache, + hb_free, + false))) + { + hb_free (cmap_cache); + cmap_cache = nullptr; + /* Normally we would retry here, but that would + * infinite-loop if the face is the empty-face. + * Just let it go and this font will be uncached if it + * happened to collide with another thread creating the + * cache at the same time. */ + // goto retry; + } + } + out: + ot_font->cmap_cache = cmap_cache; +#endif + return ot_font; } @@ -87,11 +129,7 @@ _hb_ot_font_destroy (void *font_data) hb_ot_font_t *ot_font = (hb_ot_font_t *) font_data; auto *cache = ot_font->advance_cache.get_relaxed (); - if (cache) - { - cache->fini (); - hb_free (cache); - } + hb_free (cache); hb_free (ot_font); } @@ -105,7 +143,11 @@ hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED, { const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; const hb_ot_face_t *ot_face = ot_font->ot_face; - return ot_face->cmap->get_nominal_glyph (unicode, glyph); + hb_ot_font_cmap_cache_t *cmap_cache = nullptr; +#ifndef HB_NO_OT_FONT_CMAP_CACHE + cmap_cache = ot_font->cmap_cache; +#endif + return ot_face->cmap->get_nominal_glyph (unicode, glyph, cmap_cache); } static unsigned int @@ -120,9 +162,14 @@ hb_ot_get_nominal_glyphs (hb_font_t *font HB_UNUSED, { const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; const hb_ot_face_t *ot_face = ot_font->ot_face; + hb_ot_font_cmap_cache_t *cmap_cache = nullptr; +#ifndef HB_NO_OT_FONT_CMAP_CACHE + cmap_cache = ot_font->cmap_cache; +#endif return ot_face->cmap->get_nominal_glyphs (count, first_unicode, unicode_stride, - first_glyph, glyph_stride); + first_glyph, glyph_stride, + cmap_cache); } static hb_bool_t @@ -135,7 +182,13 @@ hb_ot_get_variation_glyph (hb_font_t *font HB_UNUSED, { const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; const hb_ot_face_t *ot_face = ot_font->ot_face; - return ot_face->cmap->get_variation_glyph (unicode, variation_selector, glyph); + hb_ot_font_cmap_cache_t *cmap_cache = nullptr; +#ifndef HB_NO_OT_FONT_CMAP_CACHE + cmap_cache = ot_font->cmap_cache; +#endif + return ot_face->cmap->get_variation_glyph (unicode, + variation_selector, glyph, + cmap_cache); } static void @@ -147,18 +200,21 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, unsigned advance_stride, void *user_data HB_UNUSED) { + const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; const hb_ot_face_t *ot_face = ot_font->ot_face; const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx; -#ifndef HB_NO_VAR + hb_position_t *orig_first_advance = first_advance; + +#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE) const OT::HVAR &HVAR = *hmtx.var_table; - const OT::VariationStore &varStore = &HVAR + HVAR.varStore; - OT::VariationStore::cache_t *varStore_cache = font->num_coords * count >= 128 ? varStore.create_cache () : nullptr; + const OT::ItemVariationStore &varStore = &HVAR + HVAR.varStore; + OT::ItemVariationStore::cache_t *varStore_cache = font->num_coords * count >= 128 ? varStore.create_cache () : nullptr; bool use_cache = font->num_coords; #else - OT::VariationStore::cache_t *varStore_cache = nullptr; + OT::ItemVariationStore::cache_t *varStore_cache = nullptr; bool use_cache = false; #endif @@ -175,8 +231,8 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, use_cache = false; goto out; } + new (cache) hb_ot_font_advance_cache_t; - cache->init (); if (unlikely (!ot_font->advance_cache.cmpexch (nullptr, cache))) { hb_free (cache); @@ -200,7 +256,7 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, { /* Use cache. */ if (ot_font->cached_coords_serial.get_acquire () != (int) font->serial_coords) { - ot_font->advance_cache->init (); + ot_font->advance_cache->clear (); ot_font->cached_coords_serial.set_release (font->serial_coords); } @@ -221,9 +277,21 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, } } -#ifndef HB_NO_VAR - OT::VariationStore::destroy_cache (varStore_cache); +#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE) + OT::ItemVariationStore::destroy_cache (varStore_cache); #endif + + if (font->x_strength && !font->embolden_in_place) + { + /* Emboldening. */ + hb_position_t x_strength = font->x_scale >= 0 ? font->x_strength : -font->x_strength; + first_advance = orig_first_advance; + for (unsigned int i = 0; i < count; i++) + { + *first_advance += *first_advance ? x_strength : 0; + first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); + } + } } #ifndef HB_NO_VERTICAL @@ -240,14 +308,16 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data, const hb_ot_face_t *ot_face = ot_font->ot_face; const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx; + hb_position_t *orig_first_advance = first_advance; + if (vmtx.has_data ()) { -#ifndef HB_NO_VAR +#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE) const OT::VVAR &VVAR = *vmtx.var_table; - const OT::VariationStore &varStore = &VVAR + VVAR.varStore; - OT::VariationStore::cache_t *varStore_cache = font->num_coords ? varStore.create_cache () : nullptr; + const OT::ItemVariationStore &varStore = &VVAR + VVAR.varStore; + OT::ItemVariationStore::cache_t *varStore_cache = font->num_coords ? varStore.create_cache () : nullptr; #else - OT::VariationStore::cache_t *varStore_cache = nullptr; + OT::ItemVariationStore::cache_t *varStore_cache = nullptr; #endif for (unsigned int i = 0; i < count; i++) @@ -257,8 +327,8 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data, first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } -#ifndef HB_NO_VAR - OT::VariationStore::destroy_cache (varStore_cache); +#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE) + OT::ItemVariationStore::destroy_cache (varStore_cache); #endif } else @@ -274,6 +344,18 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data, first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } } + + if (font->y_strength && !font->embolden_in_place) + { + /* Emboldening. */ + hb_position_t y_strength = font->y_scale >= 0 ? font->y_strength : -font->y_strength; + first_advance = orig_first_advance; + for (unsigned int i = 0; i < count; i++) + { + *first_advance += *first_advance ? y_strength : 0; + first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); + } + } } #endif @@ -349,14 +431,16 @@ hb_ot_get_glyph_extents (hb_font_t *font, #if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR) if (ot_face->sbix->get_extents (font, glyph, extents)) return true; if (ot_face->CBDT->get_extents (font, glyph, extents)) return true; +#endif +#if !defined(HB_NO_COLOR) && !defined(HB_NO_PAINT) + if (ot_face->COLR->get_extents (font, glyph, extents)) return true; #endif if (ot_face->glyf->get_extents (font, glyph, extents)) return true; #ifndef HB_NO_OT_FONT_CFF - if (ot_face->cff1->get_extents (font, glyph, extents)) return true; if (ot_face->cff2->get_extents (font, glyph, extents)) return true; + if (ot_face->cff1->get_extents (font, glyph, extents)) return true; #endif - // TODO Hook up side-bearings variations. return false; } @@ -401,9 +485,16 @@ hb_ot_get_font_h_extents (hb_font_t *font, hb_font_extents_t *metrics, void *user_data HB_UNUSED) { - return _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, &metrics->ascender) && - _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER, &metrics->descender) && - _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, &metrics->line_gap); + bool ret = _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, &metrics->ascender) && + _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER, &metrics->descender) && + _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, &metrics->line_gap); + + /* Embolden */ + int y_shift = font->y_strength; + if (font->y_scale < 0) y_shift = -y_shift; + metrics->ascender += y_shift; + + return ret; } #ifndef HB_NO_VERTICAL @@ -421,17 +512,69 @@ hb_ot_get_font_v_extents (hb_font_t *font, #ifndef HB_NO_DRAW static void -hb_ot_get_glyph_shape (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) +hb_ot_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) { - hb_draw_session_t draw_session (draw_funcs, draw_data, font->slant_xy); - if (font->face->table.glyf->get_path (font, glyph, draw_session)) return; + bool embolden = font->x_strength || font->y_strength; + hb_outline_t outline; + + { // Need draw_session to be destructed before emboldening. + hb_draw_session_t draw_session (embolden ? hb_outline_recording_pen_get_funcs () : draw_funcs, + embolden ? &outline : draw_data, font->slant_xy); +#ifndef HB_NO_VAR_COMPOSITES + if (!font->face->table.VARC->get_path (font, glyph, draw_session)) +#endif + // Keep the following in synch with VARC::get_path_at() + if (!font->face->table.glyf->get_path (font, glyph, draw_session)) #ifndef HB_NO_CFF - if (font->face->table.cff1->get_path (font, glyph, draw_session)) return; - if (font->face->table.cff2->get_path (font, glyph, draw_session)) return; + if (!font->face->table.cff2->get_path (font, glyph, draw_session)) + if (!font->face->table.cff1->get_path (font, glyph, draw_session)) +#endif + {} + } + + if (embolden) + { + float x_shift = font->embolden_in_place ? 0 : (float) font->x_strength / 2; + float y_shift = (float) font->y_strength / 2; + if (font->x_scale < 0) x_shift = -x_shift; + if (font->y_scale < 0) y_shift = -y_shift; + outline.embolden (font->x_strength, font->y_strength, + x_shift, y_shift); + + outline.replay (draw_funcs, draw_data); + } +} +#endif + +#ifndef HB_NO_PAINT +static void +hb_ot_paint_glyph (hb_font_t *font, + void *font_data, + hb_codepoint_t glyph, + hb_paint_funcs_t *paint_funcs, void *paint_data, + unsigned int palette, + hb_color_t foreground, + void *user_data) +{ +#ifndef HB_NO_COLOR + if (font->face->table.COLR->paint_glyph (font, glyph, paint_funcs, paint_data, palette, foreground)) return; + if (font->face->table.SVG->paint_glyph (font, glyph, paint_funcs, paint_data)) return; +#ifndef HB_NO_OT_FONT_BITMAP + if (font->face->table.CBDT->paint_glyph (font, glyph, paint_funcs, paint_data)) return; + if (font->face->table.sbix->paint_glyph (font, glyph, paint_funcs, paint_data)) return; +#endif +#endif +#ifndef HB_NO_VAR_COMPOSITES + if (font->face->table.VARC->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return; +#endif + if (font->face->table.glyf->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return; +#ifndef HB_NO_CFF + if (font->face->table.cff2->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return; + if (font->face->table.cff1->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return; #endif } #endif @@ -459,7 +602,11 @@ static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_tface->table.glyf->get_leading_bearing_with_var_unscaled (font, glyph, is_vertical, lsb); -} - -unsigned -_glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical) -{ - return font->face->table.glyf->get_advance_with_var_unscaled (font, glyph, is_vertical); -} -#endif - - #endif diff --git a/libs/harfbuzz/src/hb-ot-hdmx-table.hh b/libs/harfbuzz/src/hb-ot-hdmx-table.hh index dea2b7e29..8582dbe27 100644 --- a/libs/harfbuzz/src/hb-ot-hdmx-table.hh +++ b/libs/harfbuzz/src/hb-ot-hdmx-table.hh @@ -46,21 +46,23 @@ struct DeviceRecord template - bool serialize (hb_serialize_context_t *c, unsigned pixelSize, Iterator it) + bool serialize (hb_serialize_context_t *c, + unsigned pixelSize, + Iterator it, + const hb_vector_t new_to_old_gid_list, + unsigned num_glyphs) { TRACE_SERIALIZE (this); - unsigned length = it.len (); - - if (unlikely (!c->extend (this, length))) return_trace (false); + if (unlikely (!c->extend (this, num_glyphs))) return_trace (false); this->pixelSize = pixelSize; this->maxWidth = + it | hb_reduce (hb_max, 0u); - + it - | hb_sink (widthsZ.as_array (length)); + for (auto &_ : new_to_old_gid_list) + widthsZ[_.first] = *it++; return_trace (true); } @@ -69,6 +71,7 @@ struct DeviceRecord { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && + hb_barrier () && c->check_range (this, sizeDeviceRecord))); } @@ -76,7 +79,7 @@ struct DeviceRecord HBUINT8 maxWidth; /* Maximum width. */ UnsizedArrayOf widthsZ; /* Array of widths (numGlyphs is from the 'maxp' table). */ public: - DEFINE_SIZE_ARRAY (2, widthsZ); + DEFINE_SIZE_UNBOUNDED (2); }; @@ -87,17 +90,13 @@ struct hdmx unsigned int get_size () const { return min_size + numRecords * sizeDeviceRecord; } - const DeviceRecord& operator [] (unsigned int i) const - { - /* XXX Null(DeviceRecord) is NOT safe as it's num-glyphs lengthed. - * https://github.com/harfbuzz/harfbuzz/issues/1300 */ - if (unlikely (i >= numRecords)) return Null (DeviceRecord); - return StructAtOffset (&this->firstDeviceRecord, i * sizeDeviceRecord); - } - template - bool serialize (hb_serialize_context_t *c, unsigned version, Iterator it) + bool serialize (hb_serialize_context_t *c, + unsigned version, + Iterator it, + const hb_vector_t &new_to_old_gid_list, + unsigned num_glyphs) { TRACE_SERIALIZE (this); @@ -105,10 +104,10 @@ struct hdmx this->version = version; this->numRecords = it.len (); - this->sizeDeviceRecord = DeviceRecord::get_size (it ? (*it).second.len () : 0); + this->sizeDeviceRecord = DeviceRecord::get_size (num_glyphs); for (const hb_item_type& _ : +it) - c->start_embed ()->serialize (c, _.first, _.second); + c->start_embed ()->serialize (c, _.first, _.second, new_to_old_gid_list, num_glyphs); return_trace (c->successful ()); } @@ -118,31 +117,30 @@ struct hdmx { TRACE_SUBSET (this); - hdmx *hdmx_prime = c->serializer->start_embed (); - if (unlikely (!hdmx_prime)) return_trace (false); + auto *hdmx_prime = c->serializer->start_embed (); + unsigned num_input_glyphs = get_num_glyphs (); auto it = + hb_range ((unsigned) numRecords) - | hb_map ([c, this] (unsigned _) + | hb_map ([c, num_input_glyphs, this] (unsigned _) { const DeviceRecord *device_record = &StructAtOffset (&firstDeviceRecord, _ * sizeDeviceRecord); auto row = - + hb_range (c->plan->num_output_glyphs ()) - | hb_map (c->plan->reverse_glyph_map) - | hb_map ([this, c, device_record] (hb_codepoint_t _) + + hb_iter (c->plan->new_to_old_gid_list) + | hb_map ([num_input_glyphs, device_record] (hb_codepoint_pair_t _) { - if (c->plan->is_empty_glyph (_)) - return Null (HBUINT8); - return device_record->widthsZ.as_array (get_num_glyphs ()) [_]; + return device_record->widthsZ.as_array (num_input_glyphs) [_.second]; }) ; return hb_pair ((unsigned) device_record->pixelSize, +row); }) ; - hdmx_prime->serialize (c->serializer, version, it); + hdmx_prime->serialize (c->serializer, version, it, + c->plan->new_to_old_gid_list, + c->plan->num_output_glyphs ()); return_trace (true); } @@ -155,7 +153,9 @@ struct hdmx { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && + hb_barrier () && !hb_unsigned_mul_overflows (numRecords, sizeDeviceRecord) && + min_size + numRecords * sizeDeviceRecord > numRecords * sizeDeviceRecord && sizeDeviceRecord >= DeviceRecord::min_size && c->check_range (this, get_size ())); } diff --git a/libs/harfbuzz/src/hb-ot-head-table.hh b/libs/harfbuzz/src/hb-ot-head-table.hh index 20991aab2..4cb6c15c6 100644 --- a/libs/harfbuzz/src/hb-ot-head-table.hh +++ b/libs/harfbuzz/src/hb-ot-head-table.hh @@ -63,7 +63,25 @@ struct head bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - return_trace (serialize (c->serializer)); + head *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + + if (c->plan->normalized_coords) + { + if (unlikely (!c->serializer->check_assign (out->xMin, c->plan->head_maxp_info.xMin, + HB_SERIALIZE_ERROR_INT_OVERFLOW))) + return_trace (false); + if (unlikely (!c->serializer->check_assign (out->xMax, c->plan->head_maxp_info.xMax, + HB_SERIALIZE_ERROR_INT_OVERFLOW))) + return_trace (false); + if (unlikely (!c->serializer->check_assign (out->yMin, c->plan->head_maxp_info.yMin, + HB_SERIALIZE_ERROR_INT_OVERFLOW))) + return_trace (false); + if (unlikely (!c->serializer->check_assign (out->yMax, c->plan->head_maxp_info.yMax, + HB_SERIALIZE_ERROR_INT_OVERFLOW))) + return_trace (false); + } + return_trace (true); } enum mac_style_flag_t { @@ -85,6 +103,7 @@ struct head { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && + hb_barrier () && version.major == 1 && magicNumber == 0x5F0F3CF5u); } @@ -97,6 +116,7 @@ struct head * entire font as HBUINT32, then store * 0xB1B0AFBAu - sum. */ HBUINT32 magicNumber; /* Set to 0x5F0F3CF5u. */ + public: HBUINT16 flags; /* Bit 0: Baseline for font at y=0; * Bit 1: Left sidebearing point at x=0; * Bit 2: Instructions may depend on point size; @@ -141,6 +161,7 @@ struct head * encoded in the cmap subtables represent proper * support for those code points. * Bit 15: Reserved, set to 0. */ + protected: HBUINT16 unitsPerEm; /* Valid range is from 16 to 16384. This value * should be a power of 2 for fonts that have * TrueType outlines. */ @@ -148,10 +169,12 @@ struct head January 1, 1904. 64-bit integer */ LONGDATETIME modified; /* Number of seconds since 12:00 midnight, January 1, 1904. 64-bit integer */ + public: HBINT16 xMin; /* For all glyph bounding boxes. */ HBINT16 yMin; /* For all glyph bounding boxes. */ HBINT16 xMax; /* For all glyph bounding boxes. */ HBINT16 yMax; /* For all glyph bounding boxes. */ + protected: HBUINT16 macStyle; /* Bit 0: Bold (if set to 1); * Bit 1: Italic (if set to 1) * Bit 2: Underline (if set to 1) diff --git a/libs/harfbuzz/src/hb-ot-hhea-table.hh b/libs/harfbuzz/src/hb-ot-hhea-table.hh index d9c9bd353..27becfda3 100644 --- a/libs/harfbuzz/src/hb-ot-hhea-table.hh +++ b/libs/harfbuzz/src/hb-ot-hhea-table.hh @@ -50,7 +50,9 @@ struct _hea bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && likely (version.major == 1)); + return_trace (c->check_struct (this) && + hb_barrier () && + likely (version.major == 1)); } public: diff --git a/libs/harfbuzz/src/hb-ot-hmtx-table.hh b/libs/harfbuzz/src/hb-ot-hmtx-table.hh index 96a394ba4..493bc6e7a 100644 --- a/libs/harfbuzz/src/hb-ot-hmtx-table.hh +++ b/libs/harfbuzz/src/hb-ot-hmtx-table.hh @@ -30,7 +30,9 @@ #include "hb-open-type.hh" #include "hb-ot-maxp-table.hh" #include "hb-ot-hhea-table.hh" +#include "hb-ot-os2-table.hh" #include "hb-ot-var-hvar-table.hh" +#include "hb-ot-var-mvar-table.hh" #include "hb-ot-metrics.hh" /* @@ -49,6 +51,9 @@ _glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t gly HB_INTERNAL unsigned _glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical); +HB_INTERNAL bool +_glyf_get_leading_bearing_without_var_unscaled (hb_face_t *face, hb_codepoint_t gid, bool is_vertical, int *lsb); + namespace OT { @@ -73,13 +78,15 @@ struct hmtxvmtx return_trace (true); } - const hb_hashmap_t>* get_mtx_map (const hb_subset_plan_t *plan) const - { return T::is_horizontal ? plan->hmtx_map : plan->vmtx_map; } + const hb_hashmap_t>* get_mtx_map (const hb_subset_plan_t *plan) const + { return T::is_horizontal ? &plan->hmtx_map : &plan->vmtx_map; } - bool subset_update_header (hb_subset_plan_t *plan, - unsigned int num_hmetrics) const + bool subset_update_header (hb_subset_context_t *c, + unsigned int num_hmetrics, + const hb_hashmap_t> *mtx_map, + const hb_vector_t &bounds_vec) const { - hb_blob_t *src_blob = hb_sanitize_context_t ().reference_table (plan->source, H::tableTag); + hb_blob_t *src_blob = hb_sanitize_context_t ().reference_table (c->plan->source, H::tableTag); hb_blob_t *dest_blob = hb_blob_copy_writable_or_fail (src_blob); hb_blob_destroy (src_blob); @@ -89,9 +96,83 @@ struct hmtxvmtx unsigned int length; H *table = (H *) hb_blob_get_data (dest_blob, &length); - table->numberOfLongMetrics = num_hmetrics; + c->serializer->check_assign (table->numberOfLongMetrics, num_hmetrics, HB_SERIALIZE_ERROR_INT_OVERFLOW); - bool result = plan->add_table (H::tableTag, dest_blob); +#ifndef HB_NO_VAR + if (c->plan->normalized_coords) + { + auto &MVAR = *c->plan->source->table.MVAR; + if (T::is_horizontal) + { + HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE, caretSlopeRise); + HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN, caretSlopeRun); + HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET, caretOffset); + } + else + { + HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_VERTICAL_CARET_RISE, caretSlopeRise); + HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_VERTICAL_CARET_RUN, caretSlopeRun); + HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET, caretOffset); + } + + bool empty = true; + int min_lsb = 0x7FFF; + int min_rsb = 0x7FFF; + int max_extent = -0x7FFF; + unsigned max_adv = 0; + for (const auto _ : *mtx_map) + { + hb_codepoint_t gid = _.first; + unsigned adv = _.second.first; + int lsb = _.second.second; + max_adv = hb_max (max_adv, adv); + + if (bounds_vec[gid] != 0xFFFFFFFF) + { + empty = false; + unsigned bound_width = bounds_vec[gid]; + int rsb = adv - lsb - bound_width; + int extent = lsb + bound_width; + min_lsb = hb_min (min_lsb, lsb); + min_rsb = hb_min (min_rsb, rsb); + max_extent = hb_max (max_extent, extent); + } + } + + table->advanceMax = max_adv; + if (!empty) + { + table->minLeadingBearing = min_lsb; + table->minTrailingBearing = min_rsb; + table->maxExtent = max_extent; + } + + if (T::is_horizontal) + { + const auto &OS2 = *c->plan->source->table.OS2; + if (OS2.has_data () && + table->ascender == OS2.sTypoAscender && + table->descender == OS2.sTypoDescender && + table->lineGap == OS2.sTypoLineGap) + { + table->ascender = static_cast (roundf (OS2.sTypoAscender + + MVAR.get_var (HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, + c->plan->normalized_coords.arrayZ, + c->plan->normalized_coords.length))); + table->descender = static_cast (roundf (OS2.sTypoDescender + + MVAR.get_var (HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER, + c->plan->normalized_coords.arrayZ, + c->plan->normalized_coords.length))); + table->lineGap = static_cast (roundf (OS2.sTypoLineGap + + MVAR.get_var (HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, + c->plan->normalized_coords.arrayZ, + c->plan->normalized_coords.length))); + } + } + } +#endif + + bool result = c->plan->add_table (H::tableTag, dest_blob); hb_blob_destroy (dest_blob); return result; @@ -101,25 +182,32 @@ struct hmtxvmtx hb_requires (hb_is_iterator (Iterator))> void serialize (hb_serialize_context_t *c, Iterator it, - unsigned num_long_metrics) + const hb_vector_t new_to_old_gid_list, + unsigned num_long_metrics, + unsigned total_num_metrics) { - unsigned idx = 0; - for (auto _ : it) + LongMetric* long_metrics = c->allocate_size (num_long_metrics * LongMetric::static_size); + FWORD* short_metrics = c->allocate_size ((total_num_metrics - num_long_metrics) * FWORD::static_size); + if (!long_metrics || !short_metrics) return; + + short_metrics -= num_long_metrics; + + for (auto _ : new_to_old_gid_list) { - if (idx < num_long_metrics) + hb_codepoint_t gid = _.first; + auto mtx = *it++; + + if (gid < num_long_metrics) { - LongMetric lm; - lm.advance = _.first; - lm.sb = _.second; - if (unlikely (!c->embed (&lm))) return; + LongMetric& lm = long_metrics[gid]; + lm.advance = mtx.first; + lm.sb = mtx.second; } + // TODO(beyond-64k): This assumes that maxp.numGlyphs is 0xFFFF. + else if (gid < 0x10000u) + short_metrics[gid] = mtx.second; else - { - FWORD *sb = c->allocate_size (FWORD::static_size); - if (unlikely (!sb)) return; - *sb = _.second; - } - idx++; + ((UFWORD*) short_metrics)[gid] = mtx.first; } } @@ -127,17 +215,18 @@ struct hmtxvmtx { TRACE_SUBSET (this); - T *table_prime = c->serializer->start_embed (); - if (unlikely (!table_prime)) return_trace (false); + auto *table_prime = c->serializer->start_embed (); accelerator_t _mtx (c->plan->source); unsigned num_long_metrics; - const hb_hashmap_t> *mtx_map = get_mtx_map (c->plan); + const hb_hashmap_t> *mtx_map = get_mtx_map (c->plan); { /* Determine num_long_metrics to encode. */ auto& plan = c->plan; - num_long_metrics = plan->num_output_glyphs (); + // TODO Don't consider retaingid holes here. + + num_long_metrics = hb_min (plan->num_output_glyphs (), 0xFFFFu); unsigned int last_advance = get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 1, _mtx); while (num_long_metrics > 1 && last_advance == get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 2, _mtx)) @@ -147,29 +236,36 @@ struct hmtxvmtx } auto it = - + hb_range (c->plan->num_output_glyphs ()) - | hb_map ([c, &_mtx, mtx_map] (unsigned _) + + hb_iter (c->plan->new_to_old_gid_list) + | hb_map ([c, &_mtx, mtx_map] (hb_codepoint_pair_t _) { - if (!mtx_map->has (_)) + hb_codepoint_t new_gid = _.first; + hb_codepoint_t old_gid = _.second; + + hb_pair_t *v = nullptr; + if (!mtx_map->has (new_gid, &v)) { - hb_codepoint_t old_gid; - if (!c->plan->old_gid_for_new_gid (_, &old_gid)) - return hb_pair (0u, 0); int lsb = 0; - (void) _mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb); + if (!_mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb)) + (void) _glyf_get_leading_bearing_without_var_unscaled (c->plan->source, old_gid, !T::is_horizontal, &lsb); return hb_pair (_mtx.get_advance_without_var_unscaled (old_gid), +lsb); } - return mtx_map->get (_); + return *v; }) ; - table_prime->serialize (c->serializer, it, num_long_metrics); + table_prime->serialize (c->serializer, + it, + c->plan->new_to_old_gid_list, + num_long_metrics, + c->plan->num_output_glyphs ()); if (unlikely (c->serializer->in_error ())) return_trace (false); // Amend header num hmetrics - if (unlikely (!subset_update_header (c->plan, num_long_metrics))) + if (unlikely (!subset_update_header (c, num_long_metrics, mtx_map, + T::is_horizontal ? c->plan->bounds_width_vec : c->plan->bounds_height_vec))) return_trace (false); return_trace (true); @@ -291,8 +387,6 @@ struct hmtxvmtx /* num_bearings <= glyph < num_glyphs; * num_bearings <= num_advances */ - /* TODO Optimize */ - if (num_bearings == num_advances) return get_advance_without_var_unscaled (num_bearings - 1); @@ -304,7 +398,7 @@ struct hmtxvmtx unsigned get_advance_with_var_unscaled (hb_codepoint_t glyph, hb_font_t *font, - VariationStore::cache_t *store_cache = nullptr) const + ItemVariationStore::cache_t *store_cache = nullptr) const { unsigned int advance = get_advance_without_var_unscaled (glyph); @@ -315,9 +409,10 @@ struct hmtxvmtx if (var_table.get_length ()) return advance + roundf (var_table->get_advance_delta_unscaled (glyph, font->coords, font->num_coords, - store_cache)); // TODO Optimize?! + store_cache)); - return _glyf_get_advance_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx); + unsigned glyf_advance = _glyf_get_advance_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx); + return glyf_advance ? glyf_advance : advance; #else return advance; #endif @@ -340,19 +435,17 @@ struct hmtxvmtx /* get advance: when no variations, call get_advance_without_var_unscaled. * when there're variations, get advance value from mtx_map in subset_plan*/ unsigned get_new_gid_advance_unscaled (const hb_subset_plan_t *plan, - const hb_hashmap_t> *mtx_map, + const hb_hashmap_t> *mtx_map, unsigned new_gid, const accelerator_t &_mtx) const { - if (mtx_map->is_empty () || - (new_gid == 0 && !mtx_map->has (new_gid))) + if (mtx_map->is_empty ()) { hb_codepoint_t old_gid = 0; return plan->old_gid_for_new_gid (new_gid, &old_gid) ? _mtx.get_advance_without_var_unscaled (old_gid) : 0; } - else - { return mtx_map->get (new_gid).first; } + return mtx_map->get (new_gid).first; } protected: diff --git a/libs/harfbuzz/src/hb-ot-kern-table.hh b/libs/harfbuzz/src/hb-ot-kern-table.hh index ffa11bc24..2abda78af 100644 --- a/libs/harfbuzz/src/hb-ot-kern-table.hh +++ b/libs/harfbuzz/src/hb-ot-kern-table.hh @@ -79,12 +79,23 @@ struct KernSubTableFormat3 { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && + hb_barrier () && c->check_range (kernValueZ, kernValueCount * sizeof (FWORD) + glyphCount * 2 + leftClassCount * rightClassCount)); } + template + void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const + { + set_t set; + if (likely (glyphCount)) + set.add_range (0, glyphCount - 1); + left_set.union_ (set); + right_set.union_ (set); + } + protected: KernSubTableHeader header; @@ -121,7 +132,7 @@ struct KernSubTable { switch (get_type ()) { /* This method hooks up to hb_font_t's get_h_kerning. Only support Format0. */ - case 0: return u.format0.get_kerning (left, right); + case 0: hb_barrier (); return u.format0.get_kerning (left, right); default:return 0; } } @@ -134,22 +145,36 @@ struct KernSubTable switch (subtable_type) { case 0: return_trace (c->dispatch (u.format0)); #ifndef HB_NO_AAT_SHAPE - case 1: return_trace (u.header.apple ? c->dispatch (u.format1, std::forward (ds)...) : c->default_return_value ()); + case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); #endif case 2: return_trace (c->dispatch (u.format2)); #ifndef HB_NO_AAT_SHAPE - case 3: return_trace (u.header.apple ? c->dispatch (u.format3, std::forward (ds)...) : c->default_return_value ()); + case 3: return_trace (c->dispatch (u.format3, std::forward (ds)...)); #endif default: return_trace (c->default_return_value ()); } } + template + void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const + { + unsigned int subtable_type = get_type (); + switch (subtable_type) { + case 0: u.format0.collect_glyphs (left_set, right_set, num_glyphs); return; + case 1: u.format1.collect_glyphs (left_set, right_set, num_glyphs); return; + case 2: u.format2.collect_glyphs (left_set, right_set, num_glyphs); return; + case 3: u.format3.collect_glyphs (left_set, right_set, num_glyphs); return; + default: return; + } + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (unlikely (!u.header.sanitize (c) || - u.header.length < u.header.min_size || - !c->check_range (this, u.header.length))) return_trace (false); + if (unlikely (!(u.header.sanitize (c) && + hb_barrier () && + u.header.length >= u.header.min_size && + c->check_range (this, u.header.length)))) return_trace (false); return_trace (dispatch (c)); } @@ -286,9 +311,9 @@ struct kern bool has_state_machine () const { switch (get_type ()) { - case 0: return u.ot.has_state_machine (); + case 0: hb_barrier (); return u.ot.has_state_machine (); #ifndef HB_NO_AAT_SHAPE - case 1: return u.aat.has_state_machine (); + case 1: hb_barrier (); return u.aat.has_state_machine (); #endif default:return false; } @@ -297,9 +322,9 @@ struct kern bool has_cross_stream () const { switch (get_type ()) { - case 0: return u.ot.has_cross_stream (); + case 0: hb_barrier (); return u.ot.has_cross_stream (); #ifndef HB_NO_AAT_SHAPE - case 1: return u.aat.has_cross_stream (); + case 1: hb_barrier (); return u.aat.has_cross_stream (); #endif default:return false; } @@ -308,16 +333,17 @@ struct kern int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const { switch (get_type ()) { - case 0: return u.ot.get_h_kerning (left, right); + case 0: hb_barrier (); return u.ot.get_h_kerning (left, right); #ifndef HB_NO_AAT_SHAPE - case 1: return u.aat.get_h_kerning (left, right); + case 1: hb_barrier (); return u.aat.get_h_kerning (left, right); #endif default:return 0; } } - bool apply (AAT::hb_aat_apply_context_t *c) const - { return dispatch (c); } + bool apply (AAT::hb_aat_apply_context_t *c, + const AAT::kern_accelerator_data_t *accel_data = nullptr) const + { return dispatch (c, accel_data); } template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const @@ -337,9 +363,45 @@ struct kern { TRACE_SANITIZE (this); if (!u.version32.sanitize (c)) return_trace (false); + hb_barrier (); return_trace (dispatch (c)); } + AAT::kern_accelerator_data_t create_accelerator_data (unsigned num_glyphs) const + { + switch (get_type ()) { + case 0: hb_barrier (); return u.ot.create_accelerator_data (num_glyphs); +#ifndef HB_NO_AAT_SHAPE + case 1: hb_barrier (); return u.aat.create_accelerator_data (num_glyphs); +#endif + default:return AAT::kern_accelerator_data_t (); + } + } + + struct accelerator_t + { + accelerator_t (hb_face_t *face) + { + hb_sanitize_context_t sc; + this->table = sc.reference_table (face); + this->accel_data = this->table->create_accelerator_data (face->get_num_glyphs ()); + } + ~accelerator_t () + { + this->table.destroy (); + } + + hb_blob_t *get_blob () const { return table.get_blob (); } + + bool apply (AAT::hb_aat_apply_context_t *c) const + { + return table->apply (c, &accel_data); + } + + hb_blob_ptr_t table; + AAT::kern_accelerator_data_t accel_data; + }; + protected: union { HBUINT32 version32; @@ -353,6 +415,10 @@ struct kern DEFINE_SIZE_UNION (4, version32); }; +struct kern_accelerator_t : kern::accelerator_t { + kern_accelerator_t (hb_face_t *face) : kern::accelerator_t (face) {} +}; + } /* namespace OT */ diff --git a/libs/harfbuzz/src/hb-ot-layout-base-table.hh b/libs/harfbuzz/src/hb-ot-layout-base-table.hh index 8179e5acd..68a4e7cba 100644 --- a/libs/harfbuzz/src/hb-ot-layout-base-table.hh +++ b/libs/harfbuzz/src/hb-ot-layout-base-table.hh @@ -46,6 +46,12 @@ struct BaseCoordFormat1 return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (coordinate) : font->em_scale_x (coordinate); } + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + return_trace ((bool) c->serializer->embed (*this)); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -67,6 +73,17 @@ struct BaseCoordFormat2 return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (coordinate) : font->em_scale_x (coordinate); } + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + + return_trace (c->serializer->check_assign (out->referenceGlyph, + c->plan->glyph_map->get (referenceGlyph), + HB_SERIALIZE_ERROR_INT_OVERFLOW)); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -86,7 +103,7 @@ struct BaseCoordFormat2 struct BaseCoordFormat3 { hb_position_t get_coord (hb_font_t *font, - const VariationStore &var_store, + const ItemVariationStore &var_store, hb_direction_t direction) const { const Device &device = this+deviceTable; @@ -96,6 +113,37 @@ struct BaseCoordFormat3 : font->em_scale_x (coordinate) + device.get_x_delta (font, var_store); } + void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const + { + unsigned varidx = (this+deviceTable).get_variation_index (); + varidx_set.add (varidx); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + + if (!c->plan->pinned_at_default) + { + unsigned var_idx = (this+deviceTable).get_variation_index (); + if (var_idx != VarIdx::NO_VARIATION) + { + hb_pair_t *v; + if (!c->plan->base_variation_idx_map.has (var_idx, &v)) + return_trace (false); + + if (unlikely (!c->serializer->check_assign (out->coordinate, coordinate + hb_second (*v), + HB_SERIALIZE_ERROR_INT_OVERFLOW))) + return_trace (false); + } + } + return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable, + this, 0, + hb_serialize_context_t::Head, + &c->plan->base_variation_idx_map)); + } bool sanitize (hb_sanitize_context_t *c) const { @@ -120,25 +168,47 @@ struct BaseCoord bool has_data () const { return u.format; } hb_position_t get_coord (hb_font_t *font, - const VariationStore &var_store, + const ItemVariationStore &var_store, hb_direction_t direction) const { switch (u.format) { - case 1: return u.format1.get_coord (font, direction); - case 2: return u.format2.get_coord (font, direction); - case 3: return u.format3.get_coord (font, var_store, direction); + case 1: hb_barrier (); return u.format1.get_coord (font, direction); + case 2: hb_barrier (); return u.format2.get_coord (font, direction); + case 3: hb_barrier (); return u.format3.get_coord (font, var_store, direction); default:return 0; } } + void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const + { + switch (u.format) { + case 3: hb_barrier (); u.format3.collect_variation_indices (varidx_set); + default:return; + } + } + + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const + { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); + TRACE_DISPATCH (this, u.format); + switch (u.format) { + case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward (ds)...)); + case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward (ds)...)); + case 3: hb_barrier (); return_trace (c->dispatch (u.format3, std::forward (ds)...)); + default:return_trace (c->default_return_value ()); + } + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (unlikely (!u.format.sanitize (c))) return_trace (false); + hb_barrier (); switch (u.format) { - case 1: return_trace (u.format1.sanitize (c)); - case 2: return_trace (u.format2.sanitize (c)); - case 3: return_trace (u.format3.sanitize (c)); + case 1: hb_barrier (); return_trace (u.format1.sanitize (c)); + case 2: hb_barrier (); return_trace (u.format2.sanitize (c)); + case 3: hb_barrier (); return_trace (u.format3.sanitize (c)); default:return_trace (false); } } @@ -160,18 +230,43 @@ struct FeatMinMaxRecord bool has_data () const { return tag; } + hb_tag_t get_feature_tag () const { return tag; } + void get_min_max (const BaseCoord **min, const BaseCoord **max) const { if (likely (min)) *min = &(this+minCoord); if (likely (max)) *max = &(this+maxCoord); } + void collect_variation_indices (const hb_subset_plan_t* plan, + const void *base, + hb_set_t& varidx_set /* OUT */) const + { + if (!plan->layout_features.has (tag)) + return; + + (base+minCoord).collect_variation_indices (varidx_set); + (base+maxCoord).collect_variation_indices (varidx_set); + } + + bool subset (hb_subset_context_t *c, + const void *base) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + if (!(out->minCoord.serialize_subset (c, minCoord, base))) + return_trace (false); + + return_trace (out->maxCoord.serialize_subset (c, maxCoord, base)); + } + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && - minCoord.sanitize (c, this) && - maxCoord.sanitize (c, this))); + minCoord.sanitize (c, base) && + maxCoord.sanitize (c, base))); } protected: @@ -187,7 +282,6 @@ struct FeatMinMaxRecord * of MinMax table (may be NULL) */ public: DEFINE_SIZE_STATIC (8); - }; struct MinMax @@ -206,6 +300,39 @@ struct MinMax } } + void collect_variation_indices (const hb_subset_plan_t* plan, + hb_set_t& varidx_set /* OUT */) const + { + (this+minCoord).collect_variation_indices (varidx_set); + (this+maxCoord).collect_variation_indices (varidx_set); + for (const FeatMinMaxRecord& record : featMinMaxRecords) + record.collect_variation_indices (plan, this, varidx_set); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); + + if (!(out->minCoord.serialize_subset (c, minCoord, this)) || + !(out->maxCoord.serialize_subset (c, maxCoord, this))) + return_trace (false); + + unsigned len = 0; + for (const FeatMinMaxRecord& _ : featMinMaxRecords) + { + hb_tag_t feature_tag = _.get_feature_tag (); + if (!c->plan->layout_features.has (feature_tag)) + continue; + + if (!_.subset (c, this)) return false; + len++; + } + return_trace (c->serializer->check_assign (out->featMinMaxRecords.len, len, + HB_SERIALIZE_ERROR_INT_OVERFLOW)); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -240,6 +367,26 @@ struct BaseValues return this+baseCoords[baseline_tag_index]; } + void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const + { + for (const auto& _ : baseCoords) + (this+_).collect_variation_indices (varidx_set); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); + out->defaultIndex = defaultIndex; + + for (const auto& _ : baseCoords) + if (!subset_offset_array (c, out->baseCoords, this) (_)) + return_trace (false); + + return_trace (bool (out->baseCoords)); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -268,13 +415,28 @@ struct BaseLangSysRecord bool has_data () const { return baseLangSysTag; } - const MinMax &get_min_max () const { return this+minMax; } + const MinMax &get_min_max (const void* base) const { return base+minMax; } + + void collect_variation_indices (const void* base, + const hb_subset_plan_t* plan, + hb_set_t& varidx_set /* OUT */) const + { (base+minMax).collect_variation_indices (plan, varidx_set); } + + bool subset (hb_subset_context_t *c, + const void *base) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + + return_trace (out->minMax.serialize_subset (c, minMax, base)); + } bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && - minMax.sanitize (c, this))); + minMax.sanitize (c, base))); } protected: @@ -291,13 +453,43 @@ struct BaseScript const MinMax &get_min_max (hb_tag_t language_tag) const { const BaseLangSysRecord& record = baseLangSysRecords.bsearch (language_tag); - return record.has_data () ? record.get_min_max () : this+defaultMinMax; + return record.has_data () ? record.get_min_max (this) : this+defaultMinMax; } const BaseCoord &get_base_coord (int baseline_tag_index) const { return (this+baseValues).get_base_coord (baseline_tag_index); } - bool has_data () const { return baseValues; } + bool has_values () const { return baseValues; } + bool has_min_max () const { return defaultMinMax; /* TODO What if only per-language is present? */ } + + void collect_variation_indices (const hb_subset_plan_t* plan, + hb_set_t& varidx_set /* OUT */) const + { + (this+baseValues).collect_variation_indices (varidx_set); + (this+defaultMinMax).collect_variation_indices (plan, varidx_set); + + for (const BaseLangSysRecord& _ : baseLangSysRecords) + _.collect_variation_indices (this, plan, varidx_set); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); + + if (baseValues && !out->baseValues.serialize_subset (c, baseValues, this)) + return_trace (false); + + if (defaultMinMax && !out->defaultMinMax.serialize_subset (c, defaultMinMax, this)) + return_trace (false); + + for (const auto& _ : baseLangSysRecords) + if (!_.subset (c, this)) return_trace (false); + + return_trace (c->serializer->check_assign (out->baseLangSysRecords.len, baseLangSysRecords.len, + HB_SERIALIZE_ERROR_INT_OVERFLOW)); + } bool sanitize (hb_sanitize_context_t *c) const { @@ -331,9 +523,31 @@ struct BaseScriptRecord bool has_data () const { return baseScriptTag; } + hb_tag_t get_script_tag () const { return baseScriptTag; } + const BaseScript &get_base_script (const BaseScriptList *list) const { return list+baseScript; } + void collect_variation_indices (const hb_subset_plan_t* plan, + const void* list, + hb_set_t& varidx_set /* OUT */) const + { + if (!plan->layout_scripts.has (baseScriptTag)) + return; + + (list+baseScript).collect_variation_indices (plan, varidx_set); + } + + bool subset (hb_subset_context_t *c, + const void *base) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + + return_trace (out->baseScript.serialize_subset (c, baseScript, base)); + } + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); @@ -360,6 +574,33 @@ struct BaseScriptList return record->has_data () ? record->get_base_script (this) : Null (BaseScript); } + void collect_variation_indices (const hb_subset_plan_t* plan, + hb_set_t& varidx_set /* OUT */) const + { + for (const BaseScriptRecord& _ : baseScriptRecords) + _.collect_variation_indices (plan, this, varidx_set); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); + + unsigned len = 0; + for (const BaseScriptRecord& _ : baseScriptRecords) + { + hb_tag_t script_tag = _.get_script_tag (); + if (!c->plan->layout_scripts.has (script_tag)) + continue; + + if (!_.subset (c, this)) return false; + len++; + } + return_trace (c->serializer->check_assign (out->baseScriptRecords.len, len, + HB_SERIALIZE_ERROR_INT_OVERFLOW)); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -383,7 +624,7 @@ struct Axis const BaseCoord **coord) const { const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag); - if (!base_script.has_data ()) + if (!base_script.has_values ()) { *coord = nullptr; return false; @@ -410,7 +651,7 @@ struct Axis const BaseCoord **max_coord) const { const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag); - if (!base_script.has_data ()) + if (!base_script.has_min_max ()) { *min_coord = *max_coord = nullptr; return false; @@ -421,12 +662,26 @@ struct Axis return true; } + void collect_variation_indices (const hb_subset_plan_t* plan, + hb_set_t& varidx_set /* OUT */) const + { (this+baseScriptList).collect_variation_indices (plan, varidx_set); } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + + out->baseTagList.serialize_copy (c->serializer, baseTagList, this); + return_trace (out->baseScriptList.serialize_subset (c, baseScriptList, this)); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && - (this+baseTagList).sanitize (c) && - (this+baseScriptList).sanitize (c))); + baseTagList.sanitize (c, this) && + baseScriptList.sanitize (c, this))); } protected: @@ -452,8 +707,77 @@ struct BASE const Axis &get_axis (hb_direction_t direction) const { return HB_DIRECTION_IS_VERTICAL (direction) ? this+vAxis : this+hAxis; } - const VariationStore &get_var_store () const - { return version.to_int () < 0x00010001u ? Null (VariationStore) : this+varStore; } + bool has_var_store () const + { return version.to_int () >= 0x00010001u && varStore != 0; } + + const ItemVariationStore &get_var_store () const + { return version.to_int () < 0x00010001u ? Null (ItemVariationStore) : this+varStore; } + + void collect_variation_indices (const hb_subset_plan_t* plan, + hb_set_t& varidx_set /* OUT */) const + { + (this+hAxis).collect_variation_indices (plan, varidx_set); + (this+vAxis).collect_variation_indices (plan, varidx_set); + } + + bool subset_varstore (hb_subset_context_t *c, + BASE *out /* OUT */) const + { + TRACE_SUBSET (this); + if (!c->serializer->allocate_size> (Offset32To::static_size)) + return_trace (false); + if (!c->plan->normalized_coords) + return_trace (out->varStore.serialize_subset (c, varStore, this, c->plan->base_varstore_inner_maps.as_array ())); + + if (c->plan->all_axes_pinned) + return_trace (true); + + item_variations_t item_vars; + if (!item_vars.instantiate (this+varStore, c->plan, true, true, + c->plan->base_varstore_inner_maps.as_array ())) + return_trace (false); + + if (!out->varStore.serialize_serialize (c->serializer, + item_vars.has_long_word (), + c->plan->axis_tags, + item_vars.get_region_list (), + item_vars.get_vardata_encodings ())) + return_trace (false); + + const hb_map_t &varidx_map = item_vars.get_varidx_map (); + /* base_variation_idx_map in the plan is old_varidx->(varidx, delta) + * mapping, new varidx is generated for subsetting, we need to remap this + * after instancing */ + for (auto _ : c->plan->base_variation_idx_map.iter_ref ()) + { + uint32_t varidx = _.second.first; + uint32_t *new_varidx; + if (varidx_map.has (varidx, &new_varidx)) + _.second.first = *new_varidx; + else + _.second.first = HB_OT_LAYOUT_NO_VARIATIONS_INDEX; + } + return_trace (true); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); + + out->version = version; + if (has_var_store () && !subset_varstore (c, out)) + return_trace (false); + + if (hAxis && !out->hAxis.serialize_subset (c, hAxis, this)) + return_trace (false); + + if (vAxis && !out->vAxis.serialize_subset (c, vAxis, this)) + return_trace (false); + + return_trace (true); + } bool get_baseline (hb_font_t *font, hb_tag_t baseline_tag, @@ -473,21 +797,20 @@ struct BASE return true; } - /* TODO: Expose this separately sometime? */ bool get_min_max (hb_font_t *font, hb_direction_t direction, hb_tag_t script_tag, hb_tag_t language_tag, hb_tag_t feature_tag, hb_position_t *min, - hb_position_t *max) + hb_position_t *max) const { const BaseCoord *min_coord, *max_coord; if (!get_axis (direction).get_min_max (script_tag, language_tag, feature_tag, &min_coord, &max_coord)) return false; - const VariationStore &var_store = get_var_store (); + const ItemVariationStore &var_store = get_var_store (); if (likely (min && min_coord)) *min = min_coord->get_coord (font, var_store, direction); if (likely (max && max_coord)) *max = max_coord->get_coord (font, var_store, direction); return true; @@ -497,6 +820,7 @@ struct BASE { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && + hb_barrier () && likely (version.major == 1) && hAxis.sanitize (c, this) && vAxis.sanitize (c, this) && @@ -509,7 +833,7 @@ struct BASE * of BASE table (may be NULL) */ Offset16TovAxis; /* Offset to vertical Axis table, from beginning * of BASE table (may be NULL) */ - Offset32To + Offset32To varStore; /* Offset to the table of Item Variation * Store--from beginning of BASE * header (may be NULL). Introduced diff --git a/libs/harfbuzz/src/hb-ot-layout-common.hh b/libs/harfbuzz/src/hb-ot-layout-common.hh index 579abf011..757b05031 100644 --- a/libs/harfbuzz/src/hb-ot-layout-common.hh +++ b/libs/harfbuzz/src/hb-ot-layout-common.hh @@ -44,42 +44,6 @@ using OT::Layout::Common::RangeRecord; using OT::Layout::SmallTypes; using OT::Layout::MediumTypes; -#ifndef HB_MAX_NESTING_LEVEL -#define HB_MAX_NESTING_LEVEL 64 -#endif -#ifndef HB_MAX_CONTEXT_LENGTH -#define HB_MAX_CONTEXT_LENGTH 64 -#endif -#ifndef HB_CLOSURE_MAX_STAGES -/* - * The maximum number of times a lookup can be applied during shaping. - * Used to limit the number of iterations of the closure algorithm. - * This must be larger than the number of times add_gsub_pause() is - * called in a collect_features call of any shaper. - */ -#define HB_CLOSURE_MAX_STAGES 12 -#endif - -#ifndef HB_MAX_SCRIPTS -#define HB_MAX_SCRIPTS 500 -#endif - -#ifndef HB_MAX_LANGSYS -#define HB_MAX_LANGSYS 2000 -#endif - -#ifndef HB_MAX_LANGSYS_FEATURE_COUNT -#define HB_MAX_LANGSYS_FEATURE_COUNT 50000 -#endif - -#ifndef HB_MAX_FEATURE_INDICES -#define HB_MAX_FEATURE_INDICES 1500 -#endif - -#ifndef HB_MAX_LOOKUP_VISIT_COUNT -#define HB_MAX_LOOKUP_VISIT_COUNT 35000 -#endif - namespace OT { @@ -91,19 +55,22 @@ static bool ClassDef_remap_and_serialize ( hb_serialize_context_t *c, const hb_set_t &klasses, bool use_class_zero, - hb_sorted_vector_t> &glyph_and_klass, /* IN/OUT */ + hb_sorted_vector_t &glyph_and_klass, /* IN/OUT */ hb_map_t *klass_map /*IN/OUT*/); struct hb_collect_feature_substitutes_with_var_context_t { const hb_map_t *axes_index_tag_map; - const hb_hashmap_t *axes_location; + const hb_hashmap_t *axes_location; hb_hashmap_t> *record_cond_idx_map; hb_hashmap_t *feature_substitutes_map; + hb_set_t& catch_all_record_feature_idxes; // not stored in subset_plan hb_set_t *feature_indices; bool apply; + bool variation_applied; + bool universal; unsigned cur_record_idx; hb_hashmap_t, unsigned> *conditionset_map; }; @@ -175,6 +142,8 @@ struct hb_subset_layout_context_t : const hb_map_t *feature_index_map; const hb_hashmap_t *feature_substitutes_map; hb_hashmap_t> *feature_record_cond_idx_map; + const hb_set_t *catch_all_record_feature_idxes; + const hb_hashmap_t> *feature_idx_tag_map; unsigned cur_script_index; unsigned cur_feature_var_record_idx; @@ -192,19 +161,23 @@ struct hb_subset_layout_context_t : { if (tag_ == HB_OT_TAG_GSUB) { - lookup_index_map = c_->plan->gsub_lookups; - script_langsys_map = c_->plan->gsub_langsys; - feature_index_map = c_->plan->gsub_features; - feature_substitutes_map = c_->plan->gsub_feature_substitutes_map; - feature_record_cond_idx_map = c_->plan->user_axes_location->is_empty () ? nullptr : c_->plan->gsub_feature_record_cond_idx_map; + lookup_index_map = &c_->plan->gsub_lookups; + script_langsys_map = &c_->plan->gsub_langsys; + feature_index_map = &c_->plan->gsub_features; + feature_substitutes_map = &c_->plan->gsub_feature_substitutes_map; + feature_record_cond_idx_map = c_->plan->user_axes_location.is_empty () ? nullptr : &c_->plan->gsub_feature_record_cond_idx_map; + catch_all_record_feature_idxes = &c_->plan->gsub_old_features; + feature_idx_tag_map = &c_->plan->gsub_old_feature_idx_tag_map; } else { - lookup_index_map = c_->plan->gpos_lookups; - script_langsys_map = c_->plan->gpos_langsys; - feature_index_map = c_->plan->gpos_features; - feature_substitutes_map = c_->plan->gpos_feature_substitutes_map; - feature_record_cond_idx_map = c_->plan->user_axes_location->is_empty () ? nullptr : c_->plan->gpos_feature_record_cond_idx_map; + lookup_index_map = &c_->plan->gpos_lookups; + script_langsys_map = &c_->plan->gpos_langsys; + feature_index_map = &c_->plan->gpos_features; + feature_substitutes_map = &c_->plan->gpos_feature_substitutes_map; + feature_record_cond_idx_map = c_->plan->user_axes_location.is_empty () ? nullptr : &c_->plan->gpos_feature_record_cond_idx_map; + catch_all_record_feature_idxes = &c_->plan->gpos_old_features; + feature_idx_tag_map = &c_->plan->gpos_old_feature_idx_tag_map; } } @@ -215,7 +188,7 @@ struct hb_subset_layout_context_t : unsigned lookup_index_count; }; -struct VariationStore; +struct ItemVariationStore; struct hb_collect_variation_indices_context_t : hb_dispatch_context_t { @@ -224,27 +197,15 @@ struct hb_collect_variation_indices_context_t : static return_t default_return_value () { return hb_empty_t (); } hb_set_t *layout_variation_indices; - hb_hashmap_t> *varidx_delta_map; - hb_font_t *font; - const VariationStore *var_store; const hb_set_t *glyph_set; const hb_map_t *gpos_lookups; - float *store_cache; hb_collect_variation_indices_context_t (hb_set_t *layout_variation_indices_, - hb_hashmap_t> *varidx_delta_map_, - hb_font_t *font_, - const VariationStore *var_store_, const hb_set_t *glyph_set_, - const hb_map_t *gpos_lookups_, - float *store_cache_) : + const hb_map_t *gpos_lookups_) : layout_variation_indices (layout_variation_indices_), - varidx_delta_map (varidx_delta_map_), - font (font_), - var_store (var_store_), glyph_set (glyph_set_), - gpos_lookups (gpos_lookups_), - store_cache (store_cache_) {} + gpos_lookups (gpos_lookups_) {} }; template @@ -478,7 +439,7 @@ struct IndexArray : Array16Of { if (_count) { - + this->sub_array (start_offset, _count) + + this->as_array ().sub_array (start_offset, _count) | hb_sink (hb_array (_indexes, *_count)) ; } @@ -499,6 +460,7 @@ struct FeatureParamsSize { TRACE_SANITIZE (this); if (unlikely (!c->check_struct (this))) return_trace (false); + hb_barrier (); /* This subtable has some "history", if you will. Some earlier versions of * Adobe tools calculated the offset of the FeatureParams subtable from the @@ -565,6 +527,9 @@ struct FeatureParamsSize return_trace (true); } + void collect_name_ids (hb_set_t *nameids_to_retain /* OUT */) const + { nameids_to_retain->add (subfamilyNameID); } + bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); @@ -621,6 +586,9 @@ struct FeatureParamsStylisticSet return_trace (c->check_struct (this)); } + void collect_name_ids (hb_set_t *nameids_to_retain /* OUT */) const + { nameids_to_retain->add (uiNameID); } + bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); @@ -658,7 +626,7 @@ struct FeatureParamsCharacterVariants { if (char_count) { - + characters.sub_array (start_offset, char_count) + + characters.as_array ().sub_array (start_offset, char_count) | hb_sink (hb_array (chars, *char_count)) ; } @@ -668,6 +636,19 @@ struct FeatureParamsCharacterVariants unsigned get_size () const { return min_size + characters.len * HBUINT24::static_size; } + void collect_name_ids (hb_set_t *nameids_to_retain /* OUT */) const + { + if (featUILableNameID) nameids_to_retain->add (featUILableNameID); + if (featUITooltipTextNameID) nameids_to_retain->add (featUITooltipTextNameID); + if (sampleTextNameID) nameids_to_retain->add (sampleTextNameID); + + if (!firstParamUILabelNameID || !numNamedParameters || numNamedParameters >= 0x7FFF) + return; + + unsigned last_name_id = (unsigned) firstParamUILabelNameID + (unsigned) numNamedParameters - 1; + nameids_to_retain->add_range (firstParamUILabelNameID, last_name_id); + } + bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); @@ -730,6 +711,19 @@ struct FeatureParams return_trace (true); } + void collect_name_ids (hb_tag_t tag, hb_set_t *nameids_to_retain /* OUT */) const + { +#ifdef HB_NO_LAYOUT_FEATURE_PARAMS + return; +#endif + if (tag == HB_TAG ('s','i','z','e')) + return (u.size.collect_name_ids (nameids_to_retain)); + if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */ + return (u.stylisticSet.collect_name_ids (nameids_to_retain)); + if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */ + return (u.characterVariants.collect_name_ids (nameids_to_retain)); + } + bool subset (hb_subset_context_t *c, const Tag* tag) const { TRACE_SUBSET (this); @@ -798,13 +792,19 @@ struct Feature bool intersects_lookup_indexes (const hb_map_t *lookup_indexes) const { return lookupIndex.intersects (lookup_indexes); } + void collect_name_ids (hb_tag_t tag, hb_set_t *nameids_to_retain /* OUT */) const + { + if (featureParams) + get_feature_params ().collect_name_ids (tag, nameids_to_retain); + } + bool subset (hb_subset_context_t *c, hb_subset_layout_context_t *l, const Tag *tag = nullptr) const { TRACE_SUBSET (this); auto *out = c->serializer->start_embed (*this); - if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); out->featureParams.serialize_subset (c, featureParams, this, tag); @@ -826,6 +826,7 @@ struct Feature TRACE_SANITIZE (this); if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c)))) return_trace (false); + hb_barrier (); /* Some earlier versions of Adobe tools calculated the offset of the * FeatureParams subtable from the beginning of the FeatureList table! @@ -844,6 +845,7 @@ struct Feature unsigned int orig_offset = featureParams; if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))) return_trace (false); + hb_barrier (); if (featureParams == 0 && closure && closure->tag == HB_TAG ('s','i','z','e') && @@ -906,7 +908,8 @@ struct Record { TRACE_SANITIZE (this); const Record_sanitize_closure_t closure = {tag, base}; - return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure)); + return_trace (c->check_struct (this) && + offset.sanitize (c, base, &closure)); } Tag tag; /* 4-byte Tag identifier */ @@ -932,7 +935,7 @@ struct RecordArrayOf : SortedArray16Of> { if (record_count) { - + this->sub_array (start_offset, record_count) + + this->as_array ().sub_array (start_offset, record_count) | hb_map (&Record::tag) | hb_sink (hb_array (record_tags, *record_count)) ; @@ -978,20 +981,18 @@ struct RecordListOfFeature : RecordListOf { TRACE_SUBSET (this); auto *out = c->serializer->start_embed (*this); - if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); - - unsigned count = this->len; + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); - + hb_zip (*this, hb_range (count)) - | hb_filter (l->feature_index_map, hb_second) - | hb_apply ([l, out, this] (const hb_pair_t&, unsigned>& _) + + hb_enumerate (*this) + | hb_filter (l->feature_index_map, hb_first) + | hb_apply ([l, out, this] (const hb_pair_t&>& _) { const Feature *f_sub = nullptr; const Feature **f = nullptr; - if (l->feature_substitutes_map->has (_.second, &f)) + if (l->feature_substitutes_map->has (_.first, &f)) f_sub = *f; - subset_record_array (l, out, this, f_sub) (_.first); + subset_record_array (l, out, this, f_sub) (_.second); }) ; @@ -1077,9 +1078,9 @@ struct LangSys { TRACE_SUBSET (this); auto *out = c->serializer->start_embed (*this); - if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); - const unsigned *v; + const uint32_t *v; out->reqFeatureIndex = l->feature_index_map->has (reqFeatureIndex, &v) ? *v : 0xFFFFu; if (!l->visitFeatureIndex (featureIndex.len)) @@ -1147,7 +1148,6 @@ struct Script return; } - unsigned langsys_count = get_lang_sys_count (); if (has_default_lang_sys ()) { //only collect features from non-redundant langsys @@ -1156,24 +1156,24 @@ struct Script d.collect_features (c); } - for (auto _ : + hb_zip (langSys, hb_range (langsys_count))) + for (auto _ : + hb_enumerate (langSys)) { - const LangSys& l = this+_.first.offset; + const LangSys& l = this+_.second.offset; if (!c->visitLangsys (l.get_feature_count ())) continue; if (l.compare (d, c->duplicate_feature_map)) continue; l.collect_features (c); - c->script_langsys_map->get (script_index)->add (_.second); + c->script_langsys_map->get (script_index)->add (_.first); } } else { - for (auto _ : + hb_zip (langSys, hb_range (langsys_count))) + for (auto _ : + hb_enumerate (langSys)) { - const LangSys& l = this+_.first.offset; + const LangSys& l = this+_.second.offset; if (!c->visitLangsys (l.get_feature_count ())) continue; l.collect_features (c); - c->script_langsys_map->get (script_index)->add (_.second); + c->script_langsys_map->get (script_index)->add (_.first); } } } @@ -1184,11 +1184,11 @@ struct Script { TRACE_SUBSET (this); if (!l->visitScript ()) return_trace (false); - if (tag && !c->plan->layout_scripts->has (*tag)) + if (tag && !c->plan->layout_scripts.has (*tag)) return false; auto *out = c->serializer->start_embed (*this); - if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); bool defaultLang = false; if (has_default_lang_sys ()) @@ -1211,10 +1211,9 @@ struct Script const hb_set_t *active_langsys = l->script_langsys_map->get (l->cur_script_index); if (active_langsys) { - unsigned count = langSys.len; - + hb_zip (langSys, hb_range (count)) - | hb_filter (active_langsys, hb_second) - | hb_map (hb_first) + + hb_enumerate (langSys) + | hb_filter (active_langsys, hb_first) + | hb_map (hb_second) | hb_filter ([=] (const Record& record) {return l->visitLangSys (); }) | hb_apply (subset_record_array (l, &(out->langSys), this)) ; @@ -1248,14 +1247,13 @@ struct RecordListOfScript : RecordListOf