Merge "Update HarfBuzz to 8.5.0" into main am: c9221f996c

Original change: https://android-review.googlesource.com/c/platform/external/harfbuzz_ng/+/3140580

Change-Id: I93e6e311bd275e9e0cb94e7787eed69f95c8a521
Signed-off-by: Automerger Merge Worker <[email protected]>
diff --git a/.ci/requirements-fonttools.txt b/.ci/requirements-fonttools.txt
index 508e384..2c6d28b 100644
--- a/.ci/requirements-fonttools.txt
+++ b/.ci/requirements-fonttools.txt
@@ -4,47 +4,47 @@
 #
 #    pip-compile --generate-hashes .ci/requirements-fonttools.in
 #
-fonttools==4.43.1 \
-    --hash=sha256:10003ebd81fec0192c889e63a9c8c63f88c7d72ae0460b7ba0cd2a1db246e5ad \
-    --hash=sha256:10b3922875ffcba636674f406f9ab9a559564fdbaa253d66222019d569db869c \
-    --hash=sha256:13a9a185259ed144def3682f74fdcf6596f2294e56fe62dfd2be736674500dba \
-    --hash=sha256:17dbc2eeafb38d5d0e865dcce16e313c58265a6d2d20081c435f84dc5a9d8212 \
-    --hash=sha256:18a2477c62a728f4d6e88c45ee9ee0229405e7267d7d79ce1f5ce0f3e9f8ab86 \
-    --hash=sha256:18eefac1b247049a3a44bcd6e8c8fd8b97f3cad6f728173b5d81dced12d6c477 \
-    --hash=sha256:1952c89a45caceedf2ab2506d9a95756e12b235c7182a7a0fff4f5e52227204f \
-    --hash=sha256:1cf9e974f63b1080b1d2686180fc1fbfd3bfcfa3e1128695b5de337eb9075cef \
-    --hash=sha256:1e09da7e8519e336239fbd375156488a4c4945f11c4c5792ee086dd84f784d02 \
-    --hash=sha256:2062542a7565091cea4cc14dd99feff473268b5b8afdee564f7067dd9fff5860 \
-    --hash=sha256:25d3da8a01442cbc1106490eddb6d31d7dffb38c1edbfabbcc8db371b3386d72 \
-    --hash=sha256:34f713dad41aa21c637b4e04fe507c36b986a40f7179dcc86402237e2d39dcd3 \
-    --hash=sha256:360201d46165fc0753229afe785900bc9596ee6974833124f4e5e9f98d0f592b \
-    --hash=sha256:3b7ad05b2beeebafb86aa01982e9768d61c2232f16470f9d0d8e385798e37184 \
-    --hash=sha256:4c54466f642d2116686268c3e5f35ebb10e49b0d48d41a847f0e171c785f7ac7 \
-    --hash=sha256:4d9740e3783c748521e77d3c397dc0662062c88fd93600a3c2087d3d627cd5e5 \
-    --hash=sha256:4f88cae635bfe4bbbdc29d479a297bb525a94889184bb69fa9560c2d4834ddb9 \
-    --hash=sha256:51669b60ee2a4ad6c7fc17539a43ffffc8ef69fd5dbed186a38a79c0ac1f5db7 \
-    --hash=sha256:5db46659cfe4e321158de74c6f71617e65dc92e54980086823a207f1c1c0e24b \
-    --hash=sha256:5f37e31291bf99a63328668bb83b0669f2688f329c4c0d80643acee6e63cd933 \
-    --hash=sha256:6bb5ea9076e0e39defa2c325fc086593ae582088e91c0746bee7a5a197be3da0 \
-    --hash=sha256:748015d6f28f704e7d95cd3c808b483c5fb87fd3eefe172a9da54746ad56bfb6 \
-    --hash=sha256:7bbbf8174501285049e64d174e29f9578495e1b3b16c07c31910d55ad57683d8 \
-    --hash=sha256:884ef38a5a2fd47b0c1291647b15f4e88b9de5338ffa24ee52c77d52b4dfd09c \
-    --hash=sha256:8da417431bfc9885a505e86ba706f03f598c85f5a9c54f67d63e84b9948ce590 \
-    --hash=sha256:95e974d70238fc2be5f444fa91f6347191d0e914d5d8ae002c9aa189572cc215 \
-    --hash=sha256:9648518ef687ba818db3fcc5d9aae27a369253ac09a81ed25c3867e8657a0680 \
-    --hash=sha256:9a2f0aa6ca7c9bc1058a9d0b35483d4216e0c1bbe3962bc62ce112749954c7b8 \
-    --hash=sha256:9c36da88422e0270fbc7fd959dc9749d31a958506c1d000e16703c2fce43e3d0 \
-    --hash=sha256:9c60ecfa62839f7184f741d0509b5c039d391c3aff71dc5bc57b87cc305cff3b \
-    --hash=sha256:9f727c3e3d08fd25352ed76cc3cb61486f8ed3f46109edf39e5a60fc9fecf6ca \
-    --hash=sha256:a7a06f8d95b7496e53af80d974d63516ffb263a468e614978f3899a6df52d4b3 \
-    --hash=sha256:ad0b3f6342cfa14be996971ea2b28b125ad681c6277c4cd0fbdb50340220dfb6 \
-    --hash=sha256:b2adca1b46d69dce4a37eecc096fe01a65d81a2f5c13b25ad54d5430ae430b13 \
-    --hash=sha256:b84a1c00f832feb9d0585ca8432fba104c819e42ff685fcce83537e2e7e91204 \
-    --hash=sha256:bb6d2f8ef81ea076877d76acfb6f9534a9c5f31dc94ba70ad001267ac3a8e56f \
-    --hash=sha256:bf11e2cca121df35e295bd34b309046c29476ee739753bc6bc9d5050de319273 \
-    --hash=sha256:d21099b411e2006d3c3e1f9aaf339e12037dbf7bf9337faf0e93ec915991f43b \
-    --hash=sha256:d4071bd1c183b8d0b368cc9ed3c07a0f6eb1bdfc4941c4c024c49a35429ac7cd \
-    --hash=sha256:e117a92b07407a061cde48158c03587ab97e74e7d73cb65e6aadb17af191162a \
-    --hash=sha256:f7a58eb5e736d7cf198eee94844b81c9573102ae5989ebcaa1d1a37acd04b33d \
-    --hash=sha256:fe9b1ec799b6086460a7480e0f55c447b1aca0a4eecc53e444f639e967348896
+fonttools==4.51.0 \
+    --hash=sha256:0118ef998a0699a96c7b28457f15546815015a2710a1b23a7bf6c1be60c01636 \
+    --hash=sha256:0d145976194a5242fdd22df18a1b451481a88071feadf251221af110ca8f00ce \
+    --hash=sha256:0e19bd9e9964a09cd2433a4b100ca7f34e34731e0758e13ba9a1ed6e5468cc0f \
+    --hash=sha256:0f08c901d3866a8905363619e3741c33f0a83a680d92a9f0e575985c2634fcc1 \
+    --hash=sha256:1250e818b5f8a679ad79660855528120a8f0288f8f30ec88b83db51515411fcc \
+    --hash=sha256:15c94eeef6b095831067f72c825eb0e2d48bb4cea0647c1b05c981ecba2bf39f \
+    --hash=sha256:1621ee57da887c17312acc4b0e7ac30d3a4fb0fec6174b2e3754a74c26bbed1e \
+    --hash=sha256:180194c7fe60c989bb627d7ed5011f2bef1c4d36ecf3ec64daec8302f1ae0716 \
+    --hash=sha256:278e50f6b003c6aed19bae2242b364e575bcb16304b53f2b64f6551b9c000e15 \
+    --hash=sha256:32b17504696f605e9e960647c5f64b35704782a502cc26a37b800b4d69ff3c77 \
+    --hash=sha256:3bee3f3bd9fa1d5ee616ccfd13b27ca605c2b4270e45715bd2883e9504735034 \
+    --hash=sha256:4060acc2bfa2d8e98117828a238889f13b6f69d59f4f2d5857eece5277b829ba \
+    --hash=sha256:54dcf21a2f2d06ded676e3c3f9f74b2bafded3a8ff12f0983160b13e9f2fb4a7 \
+    --hash=sha256:56fc244f2585d6c00b9bcc59e6593e646cf095a96fe68d62cd4da53dd1287b55 \
+    --hash=sha256:599bdb75e220241cedc6faebfafedd7670335d2e29620d207dd0378a4e9ccc5a \
+    --hash=sha256:5f6bc991d1610f5c3bbe997b0233cbc234b8e82fa99fc0b2932dc1ca5e5afec0 \
+    --hash=sha256:60a3409c9112aec02d5fb546f557bca6efa773dcb32ac147c6baf5f742e6258b \
+    --hash=sha256:68b3fb7775a923be73e739f92f7e8a72725fd333eab24834041365d2278c3671 \
+    --hash=sha256:76f1777d8b3386479ffb4a282e74318e730014d86ce60f016908d9801af9ca2a \
+    --hash=sha256:806e7912c32a657fa39d2d6eb1d3012d35f841387c8fc6cf349ed70b7c340039 \
+    --hash=sha256:84d7751f4468dd8cdd03ddada18b8b0857a5beec80bce9f435742abc9a851a74 \
+    --hash=sha256:865a58b6e60b0938874af0968cd0553bcd88e0b2cb6e588727117bd099eef836 \
+    --hash=sha256:8ac27f436e8af7779f0bb4d5425aa3535270494d3bc5459ed27de3f03151e4c2 \
+    --hash=sha256:8b4850fa2ef2cfbc1d1f689bc159ef0f45d8d83298c1425838095bf53ef46308 \
+    --hash=sha256:8b5ad456813d93b9c4b7ee55302208db2b45324315129d85275c01f5cb7e61a2 \
+    --hash=sha256:8e2f1a4499e3b5ee82c19b5ee57f0294673125c65b0a1ff3764ea1f9db2f9ef5 \
+    --hash=sha256:9696fe9f3f0c32e9a321d5268208a7cc9205a52f99b89479d1b035ed54c923f1 \
+    --hash=sha256:96a48e137c36be55e68845fc4284533bda2980f8d6f835e26bca79d7e2006438 \
+    --hash=sha256:a8feca65bab31479d795b0d16c9a9852902e3a3c0630678efb0b2b7941ea9c74 \
+    --hash=sha256:aefa011207ed36cd280babfaa8510b8176f1a77261833e895a9d96e57e44802f \
+    --hash=sha256:b2b92381f37b39ba2fc98c3a45a9d6383bfc9916a87d66ccb6553f7bdd129097 \
+    --hash=sha256:b3c61423f22165541b9403ee39874dcae84cd57a9078b82e1dce8cb06b07fa2e \
+    --hash=sha256:b5b48a1121117047d82695d276c2af2ee3a24ffe0f502ed581acc2673ecf1037 \
+    --hash=sha256:c18b49adc721a7d0b8dfe7c3130c89b8704baf599fb396396d07d4aa69b824a1 \
+    --hash=sha256:c5b8cab0c137ca229433570151b5c1fc6af212680b58b15abd797dcdd9dd5051 \
+    --hash=sha256:c7e91abdfae1b5c9e3a543f48ce96013f9a08c6c9668f1e6be0beabf0a569c1b \
+    --hash=sha256:cadf4e12a608ef1d13e039864f484c8a968840afa0258b0b843a0556497ea9ed \
+    --hash=sha256:dc0673361331566d7a663d7ce0f6fdcbfbdc1f59c6e3ed1165ad7202ca183c68 \
+    --hash=sha256:de7c29bdbdd35811f14493ffd2534b88f0ce1b9065316433b22d63ca1cd21f14 \
+    --hash=sha256:e9d9298be7a05bb4801f558522adbe2feea1b0b103d5294ebf24a92dd49b78e5 \
+    --hash=sha256:ee1af4be1c5afe4c96ca23badd368d8dc75f611887fb0c0dac9f71ee5d6f110e \
+    --hash=sha256:f7e89853d8bea103c8e3514b9f9dc86b5b4120afb4583b57eb10dfa5afbe0936
     # via -r requirements-fonttools.in
diff --git a/.ci/requirements.in b/.ci/requirements.in
index 74371a1..5ffa8f1 100644
--- a/.ci/requirements.in
+++ b/.ci/requirements.in
@@ -1,4 +1,5 @@
 -r requirements-fonttools.in
-meson==1.2.2
+meson==1.4.0
 gcovr==5.0
 ninja
+setuptools # https://github.com/harfbuzz/harfbuzz/issues/4475
diff --git a/.ci/requirements.txt b/.ci/requirements.txt
index d8881c4..867f5f8 100644
--- a/.ci/requirements.txt
+++ b/.ci/requirements.txt
@@ -1,147 +1,165 @@
 #
-# This file is autogenerated by pip-compile with Python 3.10
+# This file is autogenerated by pip-compile with Python 3.11
 # by the following command:
 #
-#    pip-compile --generate-hashes .ci/requirements.in
+#    pip-compile --allow-unsafe --generate-hashes --output-file=.ci/requirements.txt .ci/requirements.in
 #
-fonttools==4.43.1 \
-    --hash=sha256:10003ebd81fec0192c889e63a9c8c63f88c7d72ae0460b7ba0cd2a1db246e5ad \
-    --hash=sha256:10b3922875ffcba636674f406f9ab9a559564fdbaa253d66222019d569db869c \
-    --hash=sha256:13a9a185259ed144def3682f74fdcf6596f2294e56fe62dfd2be736674500dba \
-    --hash=sha256:17dbc2eeafb38d5d0e865dcce16e313c58265a6d2d20081c435f84dc5a9d8212 \
-    --hash=sha256:18a2477c62a728f4d6e88c45ee9ee0229405e7267d7d79ce1f5ce0f3e9f8ab86 \
-    --hash=sha256:18eefac1b247049a3a44bcd6e8c8fd8b97f3cad6f728173b5d81dced12d6c477 \
-    --hash=sha256:1952c89a45caceedf2ab2506d9a95756e12b235c7182a7a0fff4f5e52227204f \
-    --hash=sha256:1cf9e974f63b1080b1d2686180fc1fbfd3bfcfa3e1128695b5de337eb9075cef \
-    --hash=sha256:1e09da7e8519e336239fbd375156488a4c4945f11c4c5792ee086dd84f784d02 \
-    --hash=sha256:2062542a7565091cea4cc14dd99feff473268b5b8afdee564f7067dd9fff5860 \
-    --hash=sha256:25d3da8a01442cbc1106490eddb6d31d7dffb38c1edbfabbcc8db371b3386d72 \
-    --hash=sha256:34f713dad41aa21c637b4e04fe507c36b986a40f7179dcc86402237e2d39dcd3 \
-    --hash=sha256:360201d46165fc0753229afe785900bc9596ee6974833124f4e5e9f98d0f592b \
-    --hash=sha256:3b7ad05b2beeebafb86aa01982e9768d61c2232f16470f9d0d8e385798e37184 \
-    --hash=sha256:4c54466f642d2116686268c3e5f35ebb10e49b0d48d41a847f0e171c785f7ac7 \
-    --hash=sha256:4d9740e3783c748521e77d3c397dc0662062c88fd93600a3c2087d3d627cd5e5 \
-    --hash=sha256:4f88cae635bfe4bbbdc29d479a297bb525a94889184bb69fa9560c2d4834ddb9 \
-    --hash=sha256:51669b60ee2a4ad6c7fc17539a43ffffc8ef69fd5dbed186a38a79c0ac1f5db7 \
-    --hash=sha256:5db46659cfe4e321158de74c6f71617e65dc92e54980086823a207f1c1c0e24b \
-    --hash=sha256:5f37e31291bf99a63328668bb83b0669f2688f329c4c0d80643acee6e63cd933 \
-    --hash=sha256:6bb5ea9076e0e39defa2c325fc086593ae582088e91c0746bee7a5a197be3da0 \
-    --hash=sha256:748015d6f28f704e7d95cd3c808b483c5fb87fd3eefe172a9da54746ad56bfb6 \
-    --hash=sha256:7bbbf8174501285049e64d174e29f9578495e1b3b16c07c31910d55ad57683d8 \
-    --hash=sha256:884ef38a5a2fd47b0c1291647b15f4e88b9de5338ffa24ee52c77d52b4dfd09c \
-    --hash=sha256:8da417431bfc9885a505e86ba706f03f598c85f5a9c54f67d63e84b9948ce590 \
-    --hash=sha256:95e974d70238fc2be5f444fa91f6347191d0e914d5d8ae002c9aa189572cc215 \
-    --hash=sha256:9648518ef687ba818db3fcc5d9aae27a369253ac09a81ed25c3867e8657a0680 \
-    --hash=sha256:9a2f0aa6ca7c9bc1058a9d0b35483d4216e0c1bbe3962bc62ce112749954c7b8 \
-    --hash=sha256:9c36da88422e0270fbc7fd959dc9749d31a958506c1d000e16703c2fce43e3d0 \
-    --hash=sha256:9c60ecfa62839f7184f741d0509b5c039d391c3aff71dc5bc57b87cc305cff3b \
-    --hash=sha256:9f727c3e3d08fd25352ed76cc3cb61486f8ed3f46109edf39e5a60fc9fecf6ca \
-    --hash=sha256:a7a06f8d95b7496e53af80d974d63516ffb263a468e614978f3899a6df52d4b3 \
-    --hash=sha256:ad0b3f6342cfa14be996971ea2b28b125ad681c6277c4cd0fbdb50340220dfb6 \
-    --hash=sha256:b2adca1b46d69dce4a37eecc096fe01a65d81a2f5c13b25ad54d5430ae430b13 \
-    --hash=sha256:b84a1c00f832feb9d0585ca8432fba104c819e42ff685fcce83537e2e7e91204 \
-    --hash=sha256:bb6d2f8ef81ea076877d76acfb6f9534a9c5f31dc94ba70ad001267ac3a8e56f \
-    --hash=sha256:bf11e2cca121df35e295bd34b309046c29476ee739753bc6bc9d5050de319273 \
-    --hash=sha256:d21099b411e2006d3c3e1f9aaf339e12037dbf7bf9337faf0e93ec915991f43b \
-    --hash=sha256:d4071bd1c183b8d0b368cc9ed3c07a0f6eb1bdfc4941c4c024c49a35429ac7cd \
-    --hash=sha256:e117a92b07407a061cde48158c03587ab97e74e7d73cb65e6aadb17af191162a \
-    --hash=sha256:f7a58eb5e736d7cf198eee94844b81c9573102ae5989ebcaa1d1a37acd04b33d \
-    --hash=sha256:fe9b1ec799b6086460a7480e0f55c447b1aca0a4eecc53e444f639e967348896
+fonttools==4.51.0 \
+    --hash=sha256:0118ef998a0699a96c7b28457f15546815015a2710a1b23a7bf6c1be60c01636 \
+    --hash=sha256:0d145976194a5242fdd22df18a1b451481a88071feadf251221af110ca8f00ce \
+    --hash=sha256:0e19bd9e9964a09cd2433a4b100ca7f34e34731e0758e13ba9a1ed6e5468cc0f \
+    --hash=sha256:0f08c901d3866a8905363619e3741c33f0a83a680d92a9f0e575985c2634fcc1 \
+    --hash=sha256:1250e818b5f8a679ad79660855528120a8f0288f8f30ec88b83db51515411fcc \
+    --hash=sha256:15c94eeef6b095831067f72c825eb0e2d48bb4cea0647c1b05c981ecba2bf39f \
+    --hash=sha256:1621ee57da887c17312acc4b0e7ac30d3a4fb0fec6174b2e3754a74c26bbed1e \
+    --hash=sha256:180194c7fe60c989bb627d7ed5011f2bef1c4d36ecf3ec64daec8302f1ae0716 \
+    --hash=sha256:278e50f6b003c6aed19bae2242b364e575bcb16304b53f2b64f6551b9c000e15 \
+    --hash=sha256:32b17504696f605e9e960647c5f64b35704782a502cc26a37b800b4d69ff3c77 \
+    --hash=sha256:3bee3f3bd9fa1d5ee616ccfd13b27ca605c2b4270e45715bd2883e9504735034 \
+    --hash=sha256:4060acc2bfa2d8e98117828a238889f13b6f69d59f4f2d5857eece5277b829ba \
+    --hash=sha256:54dcf21a2f2d06ded676e3c3f9f74b2bafded3a8ff12f0983160b13e9f2fb4a7 \
+    --hash=sha256:56fc244f2585d6c00b9bcc59e6593e646cf095a96fe68d62cd4da53dd1287b55 \
+    --hash=sha256:599bdb75e220241cedc6faebfafedd7670335d2e29620d207dd0378a4e9ccc5a \
+    --hash=sha256:5f6bc991d1610f5c3bbe997b0233cbc234b8e82fa99fc0b2932dc1ca5e5afec0 \
+    --hash=sha256:60a3409c9112aec02d5fb546f557bca6efa773dcb32ac147c6baf5f742e6258b \
+    --hash=sha256:68b3fb7775a923be73e739f92f7e8a72725fd333eab24834041365d2278c3671 \
+    --hash=sha256:76f1777d8b3386479ffb4a282e74318e730014d86ce60f016908d9801af9ca2a \
+    --hash=sha256:806e7912c32a657fa39d2d6eb1d3012d35f841387c8fc6cf349ed70b7c340039 \
+    --hash=sha256:84d7751f4468dd8cdd03ddada18b8b0857a5beec80bce9f435742abc9a851a74 \
+    --hash=sha256:865a58b6e60b0938874af0968cd0553bcd88e0b2cb6e588727117bd099eef836 \
+    --hash=sha256:8ac27f436e8af7779f0bb4d5425aa3535270494d3bc5459ed27de3f03151e4c2 \
+    --hash=sha256:8b4850fa2ef2cfbc1d1f689bc159ef0f45d8d83298c1425838095bf53ef46308 \
+    --hash=sha256:8b5ad456813d93b9c4b7ee55302208db2b45324315129d85275c01f5cb7e61a2 \
+    --hash=sha256:8e2f1a4499e3b5ee82c19b5ee57f0294673125c65b0a1ff3764ea1f9db2f9ef5 \
+    --hash=sha256:9696fe9f3f0c32e9a321d5268208a7cc9205a52f99b89479d1b035ed54c923f1 \
+    --hash=sha256:96a48e137c36be55e68845fc4284533bda2980f8d6f835e26bca79d7e2006438 \
+    --hash=sha256:a8feca65bab31479d795b0d16c9a9852902e3a3c0630678efb0b2b7941ea9c74 \
+    --hash=sha256:aefa011207ed36cd280babfaa8510b8176f1a77261833e895a9d96e57e44802f \
+    --hash=sha256:b2b92381f37b39ba2fc98c3a45a9d6383bfc9916a87d66ccb6553f7bdd129097 \
+    --hash=sha256:b3c61423f22165541b9403ee39874dcae84cd57a9078b82e1dce8cb06b07fa2e \
+    --hash=sha256:b5b48a1121117047d82695d276c2af2ee3a24ffe0f502ed581acc2673ecf1037 \
+    --hash=sha256:c18b49adc721a7d0b8dfe7c3130c89b8704baf599fb396396d07d4aa69b824a1 \
+    --hash=sha256:c5b8cab0c137ca229433570151b5c1fc6af212680b58b15abd797dcdd9dd5051 \
+    --hash=sha256:c7e91abdfae1b5c9e3a543f48ce96013f9a08c6c9668f1e6be0beabf0a569c1b \
+    --hash=sha256:cadf4e12a608ef1d13e039864f484c8a968840afa0258b0b843a0556497ea9ed \
+    --hash=sha256:dc0673361331566d7a663d7ce0f6fdcbfbdc1f59c6e3ed1165ad7202ca183c68 \
+    --hash=sha256:de7c29bdbdd35811f14493ffd2534b88f0ce1b9065316433b22d63ca1cd21f14 \
+    --hash=sha256:e9d9298be7a05bb4801f558522adbe2feea1b0b103d5294ebf24a92dd49b78e5 \
+    --hash=sha256:ee1af4be1c5afe4c96ca23badd368d8dc75f611887fb0c0dac9f71ee5d6f110e \
+    --hash=sha256:f7e89853d8bea103c8e3514b9f9dc86b5b4120afb4583b57eb10dfa5afbe0936
     # via -r requirements-fonttools.in
 gcovr==5.0 \
     --hash=sha256:1d80264cbaadff356b3dda71b8c62b3aa803e5b3eb6d526a24932cd6660a2576 \
     --hash=sha256:8c49ebcfc5a98b56dd900c687aad0258ac86093d2f81a1417905193ab45fe69f
     # via -r requirements.in
-jinja2==3.1.2 \
-    --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \
-    --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61
+jinja2==3.1.4 \
+    --hash=sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369 \
+    --hash=sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d
     # via gcovr
-lxml==4.9.2 \
-    --hash=sha256:01d36c05f4afb8f7c20fd9ed5badca32a2029b93b1750f571ccc0b142531caf7 \
-    --hash=sha256:04876580c050a8c5341d706dd464ff04fd597095cc8c023252566a8826505726 \
-    --hash=sha256:05ca3f6abf5cf78fe053da9b1166e062ade3fa5d4f92b4ed688127ea7d7b1d03 \
-    --hash=sha256:090c6543d3696cbe15b4ac6e175e576bcc3f1ccfbba970061b7300b0c15a2140 \
-    --hash=sha256:0dc313ef231edf866912e9d8f5a042ddab56c752619e92dfd3a2c277e6a7299a \
-    --hash=sha256:0f2b1e0d79180f344ff9f321327b005ca043a50ece8713de61d1cb383fb8ac05 \
-    --hash=sha256:13598ecfbd2e86ea7ae45ec28a2a54fb87ee9b9fdb0f6d343297d8e548392c03 \
-    --hash=sha256:16efd54337136e8cd72fb9485c368d91d77a47ee2d42b057564aae201257d419 \
-    --hash=sha256:1ab8f1f932e8f82355e75dda5413a57612c6ea448069d4fb2e217e9a4bed13d4 \
-    --hash=sha256:223f4232855ade399bd409331e6ca70fb5578efef22cf4069a6090acc0f53c0e \
-    --hash=sha256:2455cfaeb7ac70338b3257f41e21f0724f4b5b0c0e7702da67ee6c3640835b67 \
-    --hash=sha256:2899456259589aa38bfb018c364d6ae7b53c5c22d8e27d0ec7609c2a1ff78b50 \
-    --hash=sha256:2a29ba94d065945944016b6b74e538bdb1751a1db6ffb80c9d3c2e40d6fa9894 \
-    --hash=sha256:2a87fa548561d2f4643c99cd13131acb607ddabb70682dcf1dff5f71f781a4bf \
-    --hash=sha256:2e430cd2824f05f2d4f687701144556646bae8f249fd60aa1e4c768ba7018947 \
-    --hash=sha256:36c3c175d34652a35475a73762b545f4527aec044910a651d2bf50de9c3352b1 \
-    --hash=sha256:3818b8e2c4b5148567e1b09ce739006acfaa44ce3156f8cbbc11062994b8e8dd \
-    --hash=sha256:3ab9fa9d6dc2a7f29d7affdf3edebf6ece6fb28a6d80b14c3b2fb9d39b9322c3 \
-    --hash=sha256:3efea981d956a6f7173b4659849f55081867cf897e719f57383698af6f618a92 \
-    --hash=sha256:4c8f293f14abc8fd3e8e01c5bd86e6ed0b6ef71936ded5bf10fe7a5efefbaca3 \
-    --hash=sha256:5344a43228767f53a9df6e5b253f8cdca7dfc7b7aeae52551958192f56d98457 \
-    --hash=sha256:58bfa3aa19ca4c0f28c5dde0ff56c520fbac6f0daf4fac66ed4c8d2fb7f22e74 \
-    --hash=sha256:5b4545b8a40478183ac06c073e81a5ce4cf01bf1734962577cf2bb569a5b3bbf \
-    --hash=sha256:5f50a1c177e2fa3ee0667a5ab79fdc6b23086bc8b589d90b93b4bd17eb0e64d1 \
-    --hash=sha256:63da2ccc0857c311d764e7d3d90f429c252e83b52d1f8f1d1fe55be26827d1f4 \
-    --hash=sha256:6749649eecd6a9871cae297bffa4ee76f90b4504a2a2ab528d9ebe912b101975 \
-    --hash=sha256:6804daeb7ef69e7b36f76caddb85cccd63d0c56dedb47555d2fc969e2af6a1a5 \
-    --hash=sha256:689bb688a1db722485e4610a503e3e9210dcc20c520b45ac8f7533c837be76fe \
-    --hash=sha256:699a9af7dffaf67deeae27b2112aa06b41c370d5e7633e0ee0aea2e0b6c211f7 \
-    --hash=sha256:6b418afe5df18233fc6b6093deb82a32895b6bb0b1155c2cdb05203f583053f1 \
-    --hash=sha256:76cf573e5a365e790396a5cc2b909812633409306c6531a6877c59061e42c4f2 \
-    --hash=sha256:7b515674acfdcadb0eb5d00d8a709868173acece5cb0be3dd165950cbfdf5409 \
-    --hash=sha256:7b770ed79542ed52c519119473898198761d78beb24b107acf3ad65deae61f1f \
-    --hash=sha256:7d2278d59425777cfcb19735018d897ca8303abe67cc735f9f97177ceff8027f \
-    --hash=sha256:7e91ee82f4199af8c43d8158024cbdff3d931df350252288f0d4ce656df7f3b5 \
-    --hash=sha256:821b7f59b99551c69c85a6039c65b75f5683bdc63270fec660f75da67469ca24 \
-    --hash=sha256:822068f85e12a6e292803e112ab876bc03ed1f03dddb80154c395f891ca6b31e \
-    --hash=sha256:8340225bd5e7a701c0fa98284c849c9b9fc9238abf53a0ebd90900f25d39a4e4 \
-    --hash=sha256:85cabf64adec449132e55616e7ca3e1000ab449d1d0f9d7f83146ed5bdcb6d8a \
-    --hash=sha256:880bbbcbe2fca64e2f4d8e04db47bcdf504936fa2b33933efd945e1b429bea8c \
-    --hash=sha256:8d0b4612b66ff5d62d03bcaa043bb018f74dfea51184e53f067e6fdcba4bd8de \
-    --hash=sha256:8e20cb5a47247e383cf4ff523205060991021233ebd6f924bca927fcf25cf86f \
-    --hash=sha256:925073b2fe14ab9b87e73f9a5fde6ce6392da430f3004d8b72cc86f746f5163b \
-    --hash=sha256:998c7c41910666d2976928c38ea96a70d1aa43be6fe502f21a651e17483a43c5 \
-    --hash=sha256:9b22c5c66f67ae00c0199f6055705bc3eb3fcb08d03d2ec4059a2b1b25ed48d7 \
-    --hash=sha256:9f102706d0ca011de571de32c3247c6476b55bb6bc65a20f682f000b07a4852a \
-    --hash=sha256:a08cff61517ee26cb56f1e949cca38caabe9ea9fbb4b1e10a805dc39844b7d5c \
-    --hash=sha256:a0a336d6d3e8b234a3aae3c674873d8f0e720b76bc1d9416866c41cd9500ffb9 \
-    --hash=sha256:a35f8b7fa99f90dd2f5dc5a9fa12332642f087a7641289ca6c40d6e1a2637d8e \
-    --hash=sha256:a38486985ca49cfa574a507e7a2215c0c780fd1778bb6290c21193b7211702ab \
-    --hash=sha256:a5da296eb617d18e497bcf0a5c528f5d3b18dadb3619fbdadf4ed2356ef8d941 \
-    --hash=sha256:a6e441a86553c310258aca15d1c05903aaf4965b23f3bc2d55f200804e005ee5 \
-    --hash=sha256:a82d05da00a58b8e4c0008edbc8a4b6ec5a4bc1e2ee0fb6ed157cf634ed7fa45 \
-    --hash=sha256:ab323679b8b3030000f2be63e22cdeea5b47ee0abd2d6a1dc0c8103ddaa56cd7 \
-    --hash=sha256:b1f42b6921d0e81b1bcb5e395bc091a70f41c4d4e55ba99c6da2b31626c44892 \
-    --hash=sha256:b23e19989c355ca854276178a0463951a653309fb8e57ce674497f2d9f208746 \
-    --hash=sha256:b264171e3143d842ded311b7dccd46ff9ef34247129ff5bf5066123c55c2431c \
-    --hash=sha256:b26a29f0b7fc6f0897f043ca366142d2b609dc60756ee6e4e90b5f762c6adc53 \
-    --hash=sha256:b64d891da92e232c36976c80ed7ebb383e3f148489796d8d31a5b6a677825efe \
-    --hash=sha256:b9cc34af337a97d470040f99ba4282f6e6bac88407d021688a5d585e44a23184 \
-    --hash=sha256:bc718cd47b765e790eecb74d044cc8d37d58562f6c314ee9484df26276d36a38 \
-    --hash=sha256:be7292c55101e22f2a3d4d8913944cbea71eea90792bf914add27454a13905df \
-    --hash=sha256:c83203addf554215463b59f6399835201999b5e48019dc17f182ed5ad87205c9 \
-    --hash=sha256:c9ec3eaf616d67db0764b3bb983962b4f385a1f08304fd30c7283954e6a7869b \
-    --hash=sha256:ca34efc80a29351897e18888c71c6aca4a359247c87e0b1c7ada14f0ab0c0fb2 \
-    --hash=sha256:ca989b91cf3a3ba28930a9fc1e9aeafc2a395448641df1f387a2d394638943b0 \
-    --hash=sha256:d02a5399126a53492415d4906ab0ad0375a5456cc05c3fc0fc4ca11771745cda \
-    --hash=sha256:d17bc7c2ccf49c478c5bdd447594e82692c74222698cfc9b5daae7ae7e90743b \
-    --hash=sha256:d5bf6545cd27aaa8a13033ce56354ed9e25ab0e4ac3b5392b763d8d04b08e0c5 \
-    --hash=sha256:d6b430a9938a5a5d85fc107d852262ddcd48602c120e3dbb02137c83d212b380 \
-    --hash=sha256:da248f93f0418a9e9d94b0080d7ebc407a9a5e6d0b57bb30db9b5cc28de1ad33 \
-    --hash=sha256:da4dd7c9c50c059aba52b3524f84d7de956f7fef88f0bafcf4ad7dde94a064e8 \
-    --hash=sha256:df0623dcf9668ad0445e0558a21211d4e9a149ea8f5666917c8eeec515f0a6d1 \
-    --hash=sha256:e5168986b90a8d1f2f9dc1b841467c74221bd752537b99761a93d2d981e04889 \
-    --hash=sha256:efa29c2fe6b4fdd32e8ef81c1528506895eca86e1d8c4657fda04c9b3786ddf9 \
-    --hash=sha256:f1496ea22ca2c830cbcbd473de8f114a320da308438ae65abad6bab7867fe38f \
-    --hash=sha256:f49e52d174375a7def9915c9f06ec4e569d235ad428f70751765f48d5926678c
+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 \
@@ -149,6 +167,7 @@
     --hash=sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575 \
     --hash=sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba \
     --hash=sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d \
+    --hash=sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd \
     --hash=sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3 \
     --hash=sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00 \
     --hash=sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155 \
@@ -157,6 +176,7 @@
     --hash=sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f \
     --hash=sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8 \
     --hash=sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b \
+    --hash=sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007 \
     --hash=sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24 \
     --hash=sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea \
     --hash=sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198 \
@@ -164,9 +184,12 @@
     --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 \
@@ -185,11 +208,13 @@
     --hash=sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9 \
     --hash=sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57 \
     --hash=sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc \
-    --hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2
+    --hash=sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc \
+    --hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2 \
+    --hash=sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11
     # via jinja2
-meson==1.2.2 \
-    --hash=sha256:4a0f04de331fbc7af3b802a844fc8838f4ccd1ded1e792ba4f8f2faf8c5fe4d6 \
-    --hash=sha256:6d0f9cb45aaf70bc032ecb894d5e22a512224b778837bc7e052588c7ce87571d
+meson==1.4.0 \
+    --hash=sha256:476a458d51fcfa322a6bdc64da5138997c542d08e6b2e49b9fa68c46fd7c4475 \
+    --hash=sha256:8fd6630c25c27f1489a8a0392b311a60481a3c161aa699b330e25935b750138d
     # via -r requirements.in
 ninja==1.11.1.1 \
     --hash=sha256:18302d96a5467ea98b68e1cae1ae4b4fb2b2a56a82b955193c637557c7273dbd \
@@ -208,7 +233,13 @@
     --hash=sha256:ecf80cf5afd09f14dcceff28cb3f11dc90fb97c999c89307aea435889cb66877 \
     --hash=sha256:fa2ba9d74acfdfbfbcf06fad1b8282de8a7a8c481d9dee45c859a8c93fcc1082
     # via -r requirements.in
-pygments==2.15.1 \
-    --hash=sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c \
-    --hash=sha256:db2db3deb4b4179f399a09054b023b6a586b76499d36965813c71aa8ed7b5fd1
+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==69.5.1 \
+    --hash=sha256:6c1fccdac05a97e598fb0ae3bbed5904ccb317337a51139dcd51453611bbb987 \
+    --hash=sha256:c636ac361bc47580504644275c9ad802c50415c7522212252c033bd15f301f32
+    # via -r requirements.in
diff --git a/.circleci/config.yml b/.circleci/config.yml
index a149b36..9a1b8a1 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -3,13 +3,13 @@
 executors:
   win32-executor:
     docker:
-      - image: cimg/base:edge-20.04
+      - image: cimg/base:2023.10
   win64-executor:
     docker:
-      - image: cimg/base:edge-20.04
+      - image: cimg/base:2023.10
   autotools-executor:
     docker:
-      - image: cimg/base:edge-20.04
+      - image: cimg/base:2023.10
 
 jobs:
 
@@ -68,22 +68,28 @@
     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 setup build --buildtype=minsize
-      - run: meson compile -Cbuild -j9
-      - run: meson test -Cbuild --print-errorlogs
+      - 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 setup build --default-library=static -Db_sanitize=address,undefined --buildtype=debugoptimized --wrap-mode=nodownload -Dexperimental_api=true
-      - run: meson compile -Cbuild -j9
-      - run: meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt
+      - run: 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:
@@ -91,11 +97,14 @@
     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 setup build --default-library=static -Db_sanitize=thread --buildtype=debugoptimized --wrap-mode=nodownload -Dexperimental_api=true
-      - run: meson compile -Cbuild -j9
-      - run: meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt
+      - run: 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:
@@ -103,16 +112,19 @@
     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 setup build --default-library=static -Db_sanitize=memory --buildtype=debugoptimized --wrap-mode=nodownload -Dauto_features=disabled -Dtests=enabled -Dexperimental_api=true
-      - run: meson compile -Cbuild -j9
-      - run: meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt
+      - run: 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
@@ -123,9 +135,12 @@
     executor: win32-executor
     steps:
       - checkout
-      - run: sudo apt update && DEBIAN_FRONTEND=noninteractive sudo apt install -y ninja-build python3 python3-pip git g++-mingw-w64-i686 zip
-      - run: pip3 install meson==0.60.0
-      - run: .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:
@@ -146,9 +161,12 @@
     executor: win64-executor
     steps:
       - checkout
-      - run: sudo apt update && DEBIAN_FRONTEND=noninteractive sudo apt install -y ninja-build python3 python3-pip git g++-mingw-w64-x86-64 zip
-      - run: pip3 install meson==0.60.0
-      - run: 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:
diff --git a/.editorconfig b/.editorconfig
index cac917b..f0b1287 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -9,7 +9,7 @@
 [*.{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
diff --git a/.github/workflows/arm-ci.yml b/.github/workflows/arm-ci.yml
index 66f75ff..5e0460f 100644
--- a/.github/workflows/arm-ci.yml
+++ b/.github/workflows/arm-ci.yml
@@ -15,7 +15,7 @@
     container:
       image: devkitpro/devkitarm:latest
     steps:
-      - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
+      - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
       - name: Configure CMake
         run: |
           cmake -S . -B build \
diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml
index f3dd587..19ef197 100644
--- a/.github/workflows/cifuzz.yml
+++ b/.github/workflows/cifuzz.yml
@@ -21,7 +21,7 @@
         fuzz-seconds: 600
         dry-run: false
     - name: Upload Crash
-      uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
+      uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
       if: failure() && steps.build.outcome == 'success'
       with:
         name: artifacts
diff --git a/.github/workflows/configs-build.yml b/.github/workflows/configs-build.yml
index a1c8a8f..0ef997b 100644
--- a/.github/workflows/configs-build.yml
+++ b/.github/workflows/configs-build.yml
@@ -14,7 +14,7 @@
     runs-on: ubuntu-20.04
 
     steps:
-    - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
+    - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
     - name: install dependencies
       run: sudo apt-get install gcc
     - name: HB_DISABLE_DEPRECATED
diff --git a/.github/workflows/coverity-scan.yml b/.github/workflows/coverity-scan.yml
index 70f3fe2..01c22b0 100644
--- a/.github/workflows/coverity-scan.yml
+++ b/.github/workflows/coverity-scan.yml
@@ -11,7 +11,7 @@
   latest:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
+      - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
 
       - run: sudo apt-get install gcc clang wget git curl pkg-config libfreetype6-dev libglib2.0-dev libicu-dev libgraphite2-dev
 
diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml
index 6eca177..9eec5c1 100644
--- a/.github/workflows/linux-ci.yml
+++ b/.github/workflows/linux-ci.yml
@@ -16,9 +16,9 @@
 
     steps:
     - name: Checkout
-      uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
+      uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
     - name: Setup Ccache
-      uses: hendrikmuhs/ccache-action@6d1841ec156c39a52b1b23a810da917ab98da1f4 # v1.2.10
+      uses: hendrikmuhs/ccache-action@c92f40bee50034e84c763e33b317c77adaa81c92 # v1.2.13
       with:
         key: ${{ github.job }}-${{ runner.os }}-${{ runner.arch }}
     - name: Install Dependencies
@@ -38,6 +38,10 @@
           pkg-config \
           python3 \
           python3-setuptools
+    - name: Setup Python
+      uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0
+      with:
+        python-version: '3.x'
     - name: Install Python Dependencies
       run: sudo pip3 install -r .ci/requirements.txt --require-hashes
     - name: Setup Meson
@@ -66,6 +70,6 @@
     - name: Generate Coverage
       run: ninja -Cbuild coverage-xml
     - name: Upload Coverage
-      uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # v3.1.4
+      uses: codecov/codecov-action@84508663e988701840491b86de86b666e8a86bed # v4.3.0
       with:
         file: build/meson-logs/coverage.xml
diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml
index 117f431..581ef91 100644
--- a/.github/workflows/macos-ci.yml
+++ b/.github/workflows/macos-ci.yml
@@ -15,9 +15,9 @@
 
     steps:
     - name: Checkout
-      uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
+      uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
     - name: Setup Ccache
-      uses: hendrikmuhs/ccache-action@6d1841ec156c39a52b1b23a810da917ab98da1f4 # v1.2.10
+      uses: hendrikmuhs/ccache-action@c92f40bee50034e84c763e33b317c77adaa81c92 # v1.2.13
       with:
         key: ${{ github.job }}-${{ runner.os }}-${{ runner.arch }}
     - name: Install Dependencies
@@ -34,11 +34,17 @@
           meson \
           ninja \
           pkg-config
+    - name: Setup Python
+      uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0
+      with:
+        python-version: '3.x'
     - 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: |
-        export PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:/usr/local/opt/libffi/lib/pkgconfig"
+        brew link --force icu4c
         ccache --version
         meson setup build \
           -Dauto_features=enabled \
@@ -55,6 +61,6 @@
     - name: Generate Coverage
       run: ninja -Cbuild coverage-xml
     - name: Upload Coverage
-      uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # v3.1.4
+      uses: codecov/codecov-action@84508663e988701840491b86de86b666e8a86bed # v4.3.0
       with:
         file: build/meson-logs/coverage.xml
diff --git a/.github/workflows/msvc-ci.yml b/.github/workflows/msvc-ci.yml
index 82ee4c2..7945dd2 100644
--- a/.github/workflows/msvc-ci.yml
+++ b/.github/workflows/msvc-ci.yml
@@ -28,18 +28,18 @@
 
     steps:
     - name: Checkout
-      uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
+      uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
     - name: Setup Ccache
-      uses: hendrikmuhs/ccache-action@6d1841ec156c39a52b1b23a810da917ab98da1f4 # v1.2.10
+      uses: hendrikmuhs/ccache-action@c92f40bee50034e84c763e33b317c77adaa81c92 # v1.2.13
       with:
         variant: sccache
         key: ${{ github.job }}-${{ matrix.os }}-${{ matrix.ARCH }}
     - name: Setup Python
-      uses: actions/setup-python@65d7f2d534ac1bc67fcd62888c5f4f3d2cb2b236 # v4.7.1
+      uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0
       with:
         python-version: '3.x'
     - name: Setup MSVC
-      uses: ilammy/msvc-dev-cmd@cec98b9d092141f74527d0afa6feb2af698cfe89 # v1.12.1
+      uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0
       with:
         arch : ${{ matrix.ARCH }}
     - name: Install Python Dependencies
diff --git a/.github/workflows/msys2-ci.yml b/.github/workflows/msys2-ci.yml
index 33fc703..2c13d68 100644
--- a/.github/workflows/msys2-ci.yml
+++ b/.github/workflows/msys2-ci.yml
@@ -33,7 +33,7 @@
         shell: msys2 {0}
     steps:
     - name: Checkout
-      uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
+      uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
     - name: Setup MSYS2
       uses: msys2/setup-msys2@cf96e00c0aab3788743aaf63b64146f0d383cee9 # v2
       with:
@@ -76,7 +76,7 @@
       run: meson test --print-errorlogs --suite=harfbuzz -Cbuild
     - name: Upload DLLs
       if: always()
-      uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
+      uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
       with:
         name: libharfbuzz-${{ matrix.MSYS2_ARCH }}
         path: ./build/src/libharfbuzz-*.dll
diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml
index cc1362e..3116b2a 100644
--- a/.github/workflows/scorecard.yml
+++ b/.github/workflows/scorecard.yml
@@ -29,12 +29,12 @@
 
     steps:
       - name: "Checkout code"
-        uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
+        uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
         with:
           persist-credentials: false
 
       - name: "Run analysis"
-        uses: ossf/scorecard-action@483ef80eb98fb506c348f7d62e28055e49fe2398 # v2.3.0
+        uses: ossf/scorecard-action@dc50aa9510b46c811795eb24b2f1ba02a914e534 # v2.3.3
         with:
           results_file: results.sarif
           results_format: sarif
@@ -51,7 +51,7 @@
       # 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@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
+        uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
         with:
           name: SARIF file
           path: results.sarif
@@ -59,6 +59,6 @@
 
       # Upload the results to GitHub's code scanning dashboard.
       - name: "Upload to code-scanning"
-        uses: github/codeql-action/upload-sarif@0116bc2df50751f9724a2e35ef1f24d22f90e4e1 # v2.22.3
+        uses: github/codeql-action/upload-sarif@ccf74c947955fd1cf117aef6a0e4e66191ef6f61 # v3.25.4
         with:
           sarif_file: results.sarif
diff --git a/Android.bp b/Android.bp
index 2e8e9e8..367fd35 100644
--- a/Android.bp
+++ b/Android.bp
@@ -95,7 +95,7 @@
         "LICENSE_APACHE2.TXT",
         "LICENSE_ISC.TXT",
         "LICENSE_OFL.TXT",
-        "src/ms-use/COPYING",  // For MIT license
+        "src/ms-use/COPYING", // For MIT license
         "LICENSE_MIT_MODERN_VARIANT.TXT",
     ],
 }
@@ -114,6 +114,7 @@
         "src/hb-subset-cff1.cc",
         "src/hb-subset-cff2.cc",
         "src/hb-subset-input.cc",
+        "src/hb-subset-instancer-iup.cc",
         "src/hb-subset-instancer-solver.cc",
         "src/hb-subset-plan.cc",
         "src/hb-subset-repacker.cc",
@@ -138,6 +139,7 @@
         "-Werror",
         "-Wno-unused-parameter",
         "-Wno-missing-field-initializers",
+        "-Wno-implicit-fallthrough",
     ],
 }
 
@@ -238,6 +240,7 @@
         "-Werror",
         "-Wno-unused-parameter",
         "-Wno-missing-field-initializers",
+        "-Wno-implicit-fallthrough",
     ],
 
     afdo: true,
@@ -284,7 +287,7 @@
     visibility: ["//visibility:private"],
     licenses: ["external_harfbuzz_license.unused.GPLv2"],
     srcs: [
-        "test/shape/data/in-house/fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf"
+        "test/shape/data/in-house/fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf",
     ],
 }
 
@@ -354,7 +357,7 @@
         // "SPDX-license-identifier-HPND-sell-variant",
     ],
     license_text: [
-        "LICENSE_HPND_SELL_VARIANT.TXT"
+        "LICENSE_HPND_SELL_VARIANT.TXT",
     ],
 }
 
@@ -383,7 +386,7 @@
     visibility: ["//visibility:private"],
     licenses: ["external_harfbuzz_license.unused.Apache-2.0"],
     srcs: [
-        "perf/fonts/Roboto-Regular.ttf"
+        "perf/fonts/Roboto-Regular.ttf",
     ],
 }
 
@@ -424,7 +427,7 @@
         "LICENSE_OFL.TXT",
         "LICENSE_APACHE2.TXT",
         "LICENSE_MIT_MODERN_VARIANT.TXT",
-        "src/ms-use/COPYING",  // For MIT license
+        "src/ms-use/COPYING", // For MIT license
     ],
 }
 
@@ -432,7 +435,6 @@
     name: "external_harfbuzz.unused.tests",
     visibility: ["//visibility:private"],
     licenses: ["external_harfbuzz_license.unused.tests"],
-    srcs: [ "test/**/*" ],
-    path: "test"
+    srcs: ["test/**/*"],
+    path: "test",
 }
-
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e22f2cf..56d5ad8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -33,6 +33,7 @@
 
 
 ## 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 +75,8 @@
   ${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 +124,7 @@
 
 if (MSVC)
   add_definitions(-wd4244 -wd4267 -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS)
+  add_definitions(-bigobj)
 endif ()
 
 
@@ -177,6 +179,8 @@
 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/")
+extract_make_variable(HB_INFO_sources ${UTILSOURCES})
+add_prefix_to_list(HB_INFO_sources "${PROJECT_SOURCE_DIR}/util/")
 
 
 file(READ configure.ac CONFIGUREAC)
@@ -340,6 +344,23 @@
   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 +378,13 @@
     # 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 +493,7 @@
 ## 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 +502,7 @@
   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 +552,18 @@
   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 +590,8 @@
 
   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 ()
@@ -635,14 +668,8 @@
       -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,19 +710,13 @@
 
 ## 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 ${HB_VIEW_sources})
+    target_link_libraries(hb-view harfbuzz-cairo harfbuzz ${CAIRO_LIBRARIESNAMES})
+  endif()
 
   add_executable(hb-shape ${HB_SHAPE_sources})
   target_link_libraries(hb-shape harfbuzz)
@@ -706,7 +727,10 @@
   add_executable(hb-ot-shape-closure ${HB_OT_SHAPE_CLOSURE_sources})
   target_link_libraries(hb-ot-shape-closure harfbuzz)
 
-  mark_as_advanced(CAIRO_INCLUDE_DIRS CAIRO_LIBRARIESNAMES)
+  if (HB_HAVE_GOBJECT)
+    add_executable(hb-info ${HB_INFO_sources})
+    target_link_libraries(hb-info harfbuzz-gobject harfbuzz)
+  endif()
 endif ()
 
 
@@ -743,7 +767,7 @@
     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})
@@ -758,6 +782,28 @@
   )
 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
@@ -780,6 +826,15 @@
     )
     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}
@@ -792,9 +847,11 @@
         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}
     )
@@ -803,6 +860,12 @@
       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}
     )
@@ -830,4 +893,5 @@
       )
     endif ()
   endif ()
+  make_hb_features_h()
 endif ()
diff --git a/LICENSE b/LICENSE
index 59a007d..4f7afad 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,3 +1,7 @@
+(c) 2017-2023 Adobe (http://www.adobe.com/).
+
+-------------------------------------------------------------------
+
 -----------------------------------------------------------
 SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
 -----------------------------------------------------------
@@ -1171,6 +1175,10 @@
 
 Copyright 2017 The Roboto Flex Project Authors (https://github.com/TypeNetwork/Roboto-Flex)
 
+-------------------------------------------------------------------
+
+Copyright 2017 The Roboto Flex Project Authors (https://github.com/TypeNetwork/Roboto-Flex)
+
 This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: http://scripts.sil.org/OFL
 
 https://scripts.sil.org/OFL
@@ -1289,6 +1297,10 @@
 
 -------------------------------------------------------------------
 
+Copyright 2021 The Anek Project Authors (https://github.com/EkType/Anek)
+
+-------------------------------------------------------------------
+
 Copyright 2021 The M+ FONTS Project Authors (https://github.com/coz-m/MPLUS_FONTS)
 
 -------------------------------------------------------------------
@@ -1325,10 +1337,30 @@
 
 -------------------------------------------------------------------
 
+Copyright 2022 The Kalnia Glaze Project Authors (https://github.com/fridamedrano/Kalnia-Glaze)
+
+-------------------------------------------------------------------
+
 Copyright 2022 The Noto Project Authors (https://github.com/notofonts/arabic)
 
 -------------------------------------------------------------------
 
+Copyright 2022 The Noto Project Authors (https://github.com/notofonts/latin-greek-cyrillic)
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: https://scripts.sil.org/OFL
+
+https://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright 2022 The Noto Project Authors (https://github.com/notofonts/oriya)
+
+-------------------------------------------------------------------
+
+Copyright 2023 The Playwrite Project Authors (https://github.com/TypeTogether/Playwrite)
+
+-------------------------------------------------------------------
+
 Copyright © 1998-2004  David Turner and Werner Lemberg
 Copyright © 2004,2007,2009  Red Hat, Inc.
 Copyright © 2011,2012  Google, Inc.
@@ -4860,6 +4892,32 @@
 ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
 PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 
+Google Author(s): Garret Rieger
+
+-------------------------------------------------------------------
+
+Copyright © 2023  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): Qunxin Liu
 
 -------------------------------------------------------------------
@@ -4890,6 +4948,54 @@
 
 -------------------------------------------------------------------
 
+Copyright © 2024  David Corbett
+
+ 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.
+
+-------------------------------------------------------------------
+
+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.
+
+-------------------------------------------------------------------
+
 Copyright ©1993–2016 by The Font Bureau, Inc. with Reserved Font Name “Zycon”
 
 https://opensource.org/licenses/OFL-1.1
diff --git a/METADATA b/METADATA
index 58aa779..14cb4a0 100644
--- a/METADATA
+++ b/METADATA
@@ -9,7 +9,7 @@
     type: GIT
     value: "https://github.com/harfbuzz/harfbuzz"
   }
-  version: "8.2.2"
+  version: "8.5.0"
   license_type: RESTRICTED
   license_note: "would be NOTICE save for GPL in:\n"
   " m4/ax_code_coverage.m4\n"
@@ -17,8 +17,8 @@
   " culp/ligatures font with CC-BY-NC-SA licensing. Google does not want to\n"
   " host CC-BY-NC* content.\n"
   last_upgrade_date {
-    year: 2023
-    month: 10
-    day: 18
+    year: 2024
+    month: 06
+    day: 20
   }
 }
diff --git a/Makefile.am b/Makefile.am
index c14b4b7..ec53d67 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -26,6 +26,7 @@
 	subprojects/ragel.wrap \
 	subprojects/packagefiles/ragel/meson.build \
 	mingw-configure.sh \
+	xkcd.png \
 	$(NULL)
 
 MAINTAINERCLEANFILES = \
diff --git a/NEWS b/NEWS
index 9154938..e705d08 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,68 @@
+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”
@@ -176,7 +241,7 @@
 ====================================
 - 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). 
+  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)
@@ -187,7 +252,7 @@
   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. 
+- 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)
@@ -931,7 +996,7 @@
   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/README.md b/README.md
index 099d4b7..da4de65 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
 [![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&amp;utm_medium=referral&amp;utm_content=harfbuzz/harfbuzz&amp;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)
@@ -13,8 +13,10 @@
 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, Qt, LibreOffice, OpenJDK, XeTeX,
-PlayStation, Microsoft Edge, Photoshop, Illustrator, InDesign,
-and other places.
+PlayStation, Microsoft Edge, Adobe Photoshop, Illustrator, InDesign,
+Godot Engine, and other places.
+
+[![xkcd-derived image](xkcd.png)](https://xkcd.com/2347/)
 
 For bug reports, mailing list, and other information please visit:
 
@@ -70,9 +72,9 @@
 
 ## 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:
diff --git a/configure.ac b/configure.ac
index fbcd257..2efadb9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
 AC_PREREQ([2.64])
 AC_INIT([HarfBuzz],
-        [8.2.2],
+        [8.5.0],
         [https://github.com/harfbuzz/harfbuzz/issues/new],
         [harfbuzz],
         [http://harfbuzz.org/])
@@ -132,7 +132,7 @@
 			[Use glib @<:@default=auto@:>@])],,
 	[with_glib=auto])
 have_glib=false
-GLIB_DEPS="glib-2.0 >= 2.19.1"
+GLIB_DEPS="glib-2.0 >= 2.30"
 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, :)
@@ -193,7 +193,7 @@
 	[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, :)
+	PKG_CHECK_MODULES(CAIRO, cairo >= 1.10, have_cairo=true, :)
 	save_libs=$LIBS
 	LIBS="$LIBS $CAIRO_LIBS"
 	AC_CHECK_FUNCS(cairo_user_font_face_set_render_color_glyph_func)
@@ -242,7 +242,7 @@
 	[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, :)
+	PKG_CHECK_MODULES(ICU, icu-uc >= 49.0, 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])
diff --git a/docs/harfbuzz-docs.xml b/docs/harfbuzz-docs.xml
index 59bf821..263ffd1 100644
--- a/docs/harfbuzz-docs.xml
+++ b/docs/harfbuzz-docs.xml
@@ -120,6 +120,9 @@
       <index id="api-index-full"><title>API Index</title><xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include></index>
       <index id="deprecated-api-index"><title>Index of deprecated API</title><xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include></index>
 
+      <index id="api-index-8-5-0"><title>Index of new symbols in 8.5.0</title><xi:include href="xml/api-index-8.5.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-8-4-0"><title>Index of new symbols in 8.4.0</title><xi:include href="xml/api-index-8.4.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-8-3-1"><title>Index of new symbols in 8.3.1</title><xi:include href="xml/api-index-8.3.1.xml"><xi:fallback /></xi:include></index>
       <index id="api-index-8-2-0"><title>Index of new symbols in 8.2.0</title><xi:include href="xml/api-index-8.2.0.xml"><xi:fallback /></xi:include></index>
       <index id="api-index-8-1-0"><title>Index of new symbols in 8.1.0</title><xi:include href="xml/api-index-8.1.0.xml"><xi:fallback /></xi:include></index>
       <index id="api-index-8-0-0"><title>Index of new symbols in 8.0.0</title><xi:include href="xml/api-index-8.0.0.xml"><xi:fallback /></xi:include></index>
diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt
index a9307f2..7082a55 100644
--- a/docs/harfbuzz-sections.txt
+++ b/docs/harfbuzz-sections.txt
@@ -83,6 +83,8 @@
 hb_buffer_get_not_found_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
@@ -327,6 +329,7 @@
 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
 </SECTION>
 
 <SECTION>
@@ -579,20 +582,20 @@
 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_has_paint
-hb_ot_color_glyph_has_paint
+hb_ot_color_glyph_get_layers
 hb_ot_color_has_palettes
-hb_ot_color_has_png
-hb_ot_color_has_svg
-hb_ot_color_palette_color_get_name_id
-hb_ot_color_palette_get_colors
 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_flags_t
@@ -883,8 +886,11 @@
 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
@@ -905,7 +911,6 @@
 hb_object_t
 hb_subset_repack_or_fail
 hb_subset_input_override_name_table
-hb_subset_input_set_axis_range
 </SECTION>
 
 <SECTION>
diff --git a/generate_notice.py b/generate_notice.py
index 5b00e40..51022fa 100644
--- a/generate_notice.py
+++ b/generate_notice.py
@@ -39,6 +39,9 @@
 
   # broken unreadable font file for fuzzing target
   "test/fuzzing/fonts/sbix-extents.ttf",
+
+  # ???
+  "xkcd.png",
 ]
 
 IGNORE_DIR_IF_NO_COPYRIGHT = [
@@ -258,6 +261,7 @@
   "util/Makefile.am",
   "util/Makefile.sources",
   "util/meson.build",
+  "util/test-hb-subset-parsing.c",
 ]
 
 class CommentType(Enum):
diff --git a/meson.build b/meson.build
index 05ab1ab..d8d8424 100644
--- a/meson.build
+++ b/meson.build
@@ -1,6 +1,6 @@
 project('harfbuzz', 'c', 'cpp',
   meson_version: '>= 0.55.0',
-  version: '8.2.2',
+  version: '8.5.0',
   default_options: [
     'cpp_eh=none',          # Just to support msvc, we are passing -fno-exceptions also anyway
     # 'cpp_rtti=false',     # Do NOT enable, wraps inherit it and ICU needs RTTI
@@ -9,6 +9,13 @@
   ],
 )
 
+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 = '>= 12.0.6'
+
 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()
@@ -22,9 +29,16 @@
 cpp = meson.get_compiler('cpp')
 null_dep = dependency('', required: false)
 
-# Enforce C++14 requirement for MSVC STL
-if ['clang', 'clang-cl'].contains(cpp.get_id()) and cpp.get_define('_MSC_FULL_VER') != ''
-  add_project_arguments('-std=c++14', language: 'cpp')
+# 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'
@@ -34,6 +48,7 @@
   # NOTE: Only add warnings here if you are sure they're spurious
   msvc_args = [
     '/wd4244', # lossy type conversion (e.g. double -> int)
+    '/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'])
@@ -72,15 +87,15 @@
 ]
 
 check_funcs = [
-  ['atexit'],
-  ['mprotect'],
-  ['sysconf'],
-  ['getpagesize'],
-  ['mmap'],
-  ['isatty'],
-  ['uselocale'],
-  ['newlocale'],
-  ['sincosf'],
+  ['atexit', {'prefix': '#include <stdlib.h>'}],
+  ['mprotect', {'prefix': '#include <sys/mman.h>'}],
+  ['sysconf', {'prefix': '#include <unistd.h>'}],
+  ['getpagesize', {'prefix': '#include <unistd.h>'}],
+  ['mmap', {'prefix': '#include <sys/mman.h>'}],
+  ['isatty', {'prefix': '#include <unistd.h>'}],
+  ['uselocale', {'prefix': '#include <locale.h>'}],
+  ['newlocale', {'prefix': '#include <locale.h>'}],
+  ['sincosf', {'prefix': '#define _GNU_SOURCE\n#include <math.h>'}],
 ]
 
 m_dep = cpp.find_library('m', required: false)
@@ -88,6 +103,7 @@
 if meson.version().version_compare('>=0.60.0')
   # pkg-config: freetype2, cmake: Freetype
   freetype_dep = dependency('freetype2', 'Freetype',
+                            version: freetype_min_version,
                             required: get_option('freetype'),
                             default_options: ['harfbuzz=disabled'],
                             allow_fallback: true)
@@ -99,15 +115,16 @@
     freetype_opt = false
   endif
   # try pkg-config name
-  freetype_dep = dependency('freetype2', method: 'pkg-config', required: freetype_opt)
+  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', method: 'cmake', required: false)
+    freetype_dep = dependency('Freetype', version: freetype_min_version, 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'],
@@ -116,10 +133,10 @@
   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'))
+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'))
@@ -127,6 +144,7 @@
 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)
@@ -138,17 +156,18 @@
     icu_opt = false
   endif
   # try pkg-config name
-  icu_dep = dependency('icu-uc', method: 'pkg-config', required: icu_opt)
+  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', method: 'cmake', components: 'uc', required: false)
+    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
@@ -165,8 +184,8 @@
 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
@@ -184,13 +203,13 @@
     # 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_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', required: cairo_ft_required)
+    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('.')
@@ -356,11 +375,12 @@
   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
@@ -375,7 +395,7 @@
     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
 
diff --git a/perf/benchmark-subset.cc b/perf/benchmark-subset.cc
index 714f540..13e282d 100644
--- a/perf/benchmark-subset.cc
+++ b/perf/benchmark-subset.cc
@@ -46,6 +46,13 @@
   {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 <typename Type, unsigned int n>
 static inline unsigned int ARRAY_LEN (const Type (&)[n]) { return n; }
 
@@ -69,6 +76,7 @@
   {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
@@ -187,6 +195,8 @@
       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,
diff --git a/src/Makefile.am b/src/Makefile.am
index ff6a6d6..71b9f5d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -174,7 +174,7 @@
 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)
+pkginclude_HEADERS = $(HBHEADERS) hb-features.h
 nodist_pkginclude_HEADERS =
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = harfbuzz.pc
@@ -443,6 +443,7 @@
 	test-algs \
 	test-array \
 	test-bimap \
+	test-cff \
 	test-iter \
 	test-machinery \
 	test-map \
@@ -477,6 +478,10 @@
 test_bimap_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
 test_bimap_LDADD = $(COMPILED_TESTS_LDADD)
 
+test_cff_SOURCES = test-cff.cc hb-static.cc
+test_cff_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
+test_cff_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)
@@ -533,11 +538,11 @@
 test_instancer_solver_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
 test_instancer_solver_LDADD = $(COMPILED_TESTS_LDADD)
 
-test_tuple_varstore_SOURCES = test-tuple-varstore.cc hb-subset-instancer-solver.cc hb-static.cc
+test_tuple_varstore_SOURCES = test-tuple-varstore.cc hb-subset-instancer-solver.cc hb-subset-instancer-iup.cc hb-static.cc
 test_tuple_varstore_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
 test_tuple_varstore_LDADD = $(COMPILED_TESTS_LDADD)
 
-test_item_varstore_SOURCES = test-item-varstore.cc hb-subset-instancer-solver.cc hb-static.cc
+test_item_varstore_SOURCES = test-item-varstore.cc hb-subset-instancer-solver.cc hb-subset-instancer-iup.cc hb-static.cc
 test_item_varstore_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
 test_item_varstore_LDADD = $(COMPILED_TESTS_LDADD)
 
diff --git a/src/Makefile.sources b/src/Makefile.sources
index fbbff53..33b5ef8 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -368,6 +368,8 @@
 	hb-subset-cff2.cc \
 	hb-subset-input.cc \
 	hb-subset-input.hh \
+	hb-subset-instancer-iup.hh \
+	hb-subset-instancer-iup.cc \
 	hb-subset-instancer-solver.hh \
 	hb-subset-instancer-solver.cc \
 	hb-subset-accelerator.hh \
diff --git a/src/OT/Color/CBDT/CBDT.hh b/src/OT/Color/CBDT/CBDT.hh
index 457039b..bcf1848 100644
--- a/src/OT/Color/CBDT/CBDT.hh
+++ b/src/OT/Color/CBDT/CBDT.hh
@@ -204,6 +204,7 @@
   {
     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));
@@ -378,6 +379,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
+		  hb_barrier () &&
 		  firstGlyphIndex <= lastGlyphIndex &&
 		  offsetToSubtable.sanitize (c, base, lastGlyphIndex - firstGlyphIndex + 1));
   }
@@ -635,6 +637,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
+		  hb_barrier () &&
 		  indexSubtableArrayOffset.sanitize (c, base, numberOfIndexSubtables) &&
 		  horizontal.sanitize (c) &&
 		  vertical.sanitize (c));
@@ -738,7 +741,9 @@
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
+		  hb_barrier () &&
 		  likely (version.major == 2 || version.major == 3) &&
+		  hb_barrier () &&
 		  sizeTables.sanitize (c, this));
   }
 
@@ -975,6 +980,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
+		  hb_barrier () &&
 		  likely (version.major == 2 || version.major == 3));
   }
 
diff --git a/src/OT/Color/COLR/COLR.hh b/src/OT/Color/COLR/COLR.hh
index 60b094e..835d87f 100644
--- a/src/OT/Color/COLR/COLR.hh
+++ b/src/OT/Color/COLR/COLR.hh
@@ -68,7 +68,7 @@
   hb_font_t *font;
   unsigned int palette_index;
   hb_color_t foreground;
-  VarStoreInstancer &instancer;
+  ItemVarStoreInstancer &instancer;
   hb_map_t current_glyphs;
   hb_map_t current_layers;
   int depth_left = HB_MAX_NESTING_LEVEL;
@@ -80,7 +80,7 @@
                       hb_font_t *font_,
                       unsigned int palette_,
                       hb_color_t foreground_,
-		      VarStoreInstancer &instancer_) :
+		      ItemVarStoreInstancer &instancer_) :
     base (base_),
     funcs (funcs_),
     data (data_),
@@ -159,23 +159,35 @@
   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_)
   {}
 };
@@ -242,18 +254,33 @@
   }
 
   void closurev1 (hb_colrv1_closure_context_t* c) const
-  { value.closurev1 (c); }
+  {
+    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 VarStoreInstancer &instancer) const
+               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);
 
-    //TODO: update varIdxBase for partial-instancing
-    return_trace (c->serializer->embed (varIdxBase));
+    VarIdx new_varidx;
+    new_varidx = varIdxBase;
+    if (varIdxBase != VarIdx::NO_VARIATION)
+    {
+      hb_pair_t<unsigned, int> *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
@@ -270,7 +297,7 @@
 
   void get_color_stop (hb_paint_context_t *c,
                        hb_color_stop_t *stop,
-		       const VarStoreInstancer &instancer) const
+		       const ItemVarStoreInstancer &instancer) const
   {
     value.get_color_stop (c, stop, varIdxBase, instancer);
   }
@@ -305,7 +332,7 @@
   { value.closurev1 (c); }
 
   bool subset (hb_subset_context_t *c,
-               const VarStoreInstancer &instancer) const
+               const ItemVarStoreInstancer &instancer) const
   {
     TRACE_SUBSET (this);
     return_trace (value.subset (c, instancer, varIdxBase));
@@ -325,7 +352,7 @@
 
   void get_color_stop (hb_paint_context_t *c,
                        hb_color_stop_t *stop,
-		       const VarStoreInstancer &instancer) const
+		       const ItemVarStoreInstancer &instancer) const
   {
     value.get_color_stop (c, stop, VarIdx::NO_VARIATION, instancer);
   }
@@ -345,10 +372,13 @@
 struct ColorStop
 {
   void closurev1 (hb_colrv1_closure_context_t* c) const
-  { c->add_palette_index (paletteIndex); }
+  {
+    c->add_palette_index (paletteIndex);
+    c->num_var_idxes = 2;
+  }
 
   bool subset (hb_subset_context_t *c,
-               const VarStoreInstancer &instancer,
+               const ItemVarStoreInstancer &instancer,
                uint32_t varIdxBase) const
   {
     TRACE_SUBSET (this);
@@ -374,7 +404,7 @@
   void get_color_stop (hb_paint_context_t *c,
                        hb_color_stop_t *out,
 		       uint32_t varIdx,
-		       const VarStoreInstancer &instancer) const
+		       const ItemVarStoreInstancer &instancer) const
   {
     out->offset = stopOffset.to_float(instancer (varIdx, 0));
     out->color = c->get_color (paletteIndex,
@@ -410,7 +440,7 @@
   }
 
   bool subset (hb_subset_context_t *c,
-               const VarStoreInstancer &instancer) const
+               const ItemVarStoreInstancer &instancer) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->start_embed (this);
@@ -439,7 +469,7 @@
                    unsigned int start,
 		   unsigned int *count,
 		   hb_color_stop_t *color_stops,
-		   const VarStoreInstancer &instancer) const
+		   const ItemVarStoreInstancer &instancer) const
   {
     unsigned int len = stops.len;
 
@@ -542,8 +572,11 @@
     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 VarStoreInstancer &instancer,
+               const ItemVarStoreInstancer &instancer,
                uint32_t varIdxBase) const
   {
     TRACE_SUBSET (this);
@@ -588,7 +621,7 @@
   void closurev1 (hb_colrv1_closure_context_t* c) const;
 
   bool subset (hb_subset_context_t *c,
-               const VarStoreInstancer &instancer HB_UNUSED) const
+               const ItemVarStoreInstancer &instancer HB_UNUSED) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (this);
@@ -617,10 +650,13 @@
 struct PaintSolid
 {
   void closurev1 (hb_colrv1_closure_context_t* c) const
-  { c->add_palette_index (paletteIndex); }
+  {
+    c->add_palette_index (paletteIndex);
+    c->num_var_idxes = 1;
+  }
 
   bool subset (hb_subset_context_t *c,
-               const VarStoreInstancer &instancer,
+               const ItemVarStoreInstancer &instancer,
                uint32_t varIdxBase) const
   {
     TRACE_SUBSET (this);
@@ -666,10 +702,13 @@
 struct PaintLinearGradient
 {
   void closurev1 (hb_colrv1_closure_context_t* c) const
-  { (this+colorLine).closurev1 (c); }
+  {
+    (this+colorLine).closurev1 (c);
+    c->num_var_idxes = 6;
+  }
 
   bool subset (hb_subset_context_t *c,
-               const VarStoreInstancer &instancer,
+               const ItemVarStoreInstancer &instancer,
                uint32_t varIdxBase) const
   {
     TRACE_SUBSET (this);
@@ -733,10 +772,13 @@
 struct PaintRadialGradient
 {
   void closurev1 (hb_colrv1_closure_context_t* c) const
-  { (this+colorLine).closurev1 (c); }
+  {
+    (this+colorLine).closurev1 (c);
+    c->num_var_idxes = 6;
+  }
 
   bool subset (hb_subset_context_t *c,
-               const VarStoreInstancer &instancer,
+               const ItemVarStoreInstancer &instancer,
                uint32_t varIdxBase) const
   {
     TRACE_SUBSET (this);
@@ -800,10 +842,13 @@
 struct PaintSweepGradient
 {
   void closurev1 (hb_colrv1_closure_context_t* c) const
-  { (this+colorLine).closurev1 (c); }
+  {
+    (this+colorLine).closurev1 (c);
+    c->num_var_idxes = 4;
+  }
 
   bool subset (hb_subset_context_t *c,
-               const VarStoreInstancer &instancer,
+               const ItemVarStoreInstancer &instancer,
                uint32_t varIdxBase) const
   {
     TRACE_SUBSET (this);
@@ -863,7 +908,7 @@
   void closurev1 (hb_colrv1_closure_context_t* c) const;
 
   bool subset (hb_subset_context_t *c,
-               const VarStoreInstancer &instancer) const
+               const ItemVarStoreInstancer &instancer) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (this);
@@ -906,7 +951,7 @@
   void closurev1 (hb_colrv1_closure_context_t* c) const;
 
   bool subset (hb_subset_context_t *c,
-               const VarStoreInstancer &instancer HB_UNUSED) const
+               const ItemVarStoreInstancer &instancer HB_UNUSED) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (this);
@@ -936,7 +981,7 @@
   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
 
   bool subset (hb_subset_context_t *c,
-               const VarStoreInstancer &instancer) const
+               const ItemVarStoreInstancer &instancer) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (this);
@@ -975,7 +1020,7 @@
   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
 
   bool subset (hb_subset_context_t *c,
-               const VarStoreInstancer &instancer,
+               const ItemVarStoreInstancer &instancer,
                uint32_t varIdxBase) const
   {
     TRACE_SUBSET (this);
@@ -1024,7 +1069,7 @@
   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
 
   bool subset (hb_subset_context_t *c,
-               const VarStoreInstancer &instancer,
+               const ItemVarStoreInstancer &instancer,
                uint32_t varIdxBase) const
   {
     TRACE_SUBSET (this);
@@ -1073,7 +1118,7 @@
   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
 
   bool subset (hb_subset_context_t *c,
-               const VarStoreInstancer &instancer,
+               const ItemVarStoreInstancer &instancer,
                uint32_t varIdxBase) const
   {
     TRACE_SUBSET (this);
@@ -1132,7 +1177,7 @@
   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
 
   bool subset (hb_subset_context_t *c,
-               const VarStoreInstancer &instancer,
+               const ItemVarStoreInstancer &instancer,
                uint32_t varIdxBase) const
   {
     TRACE_SUBSET (this);
@@ -1176,7 +1221,7 @@
   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
 
   bool subset (hb_subset_context_t *c,
-               const VarStoreInstancer &instancer,
+               const ItemVarStoreInstancer &instancer,
                uint32_t varIdxBase) const
   {
     TRACE_SUBSET (this);
@@ -1232,7 +1277,7 @@
   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
 
   bool subset (hb_subset_context_t *c,
-               const VarStoreInstancer &instancer,
+               const ItemVarStoreInstancer &instancer,
                uint32_t varIdxBase) const
   {
     TRACE_SUBSET (this);
@@ -1276,7 +1321,7 @@
   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
 
   bool subset (hb_subset_context_t *c,
-               const VarStoreInstancer &instancer,
+               const ItemVarStoreInstancer &instancer,
                uint32_t varIdxBase) const
   {
     TRACE_SUBSET (this);
@@ -1332,7 +1377,7 @@
   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
 
   bool subset (hb_subset_context_t *c,
-               const VarStoreInstancer &instancer,
+               const ItemVarStoreInstancer &instancer,
                uint32_t varIdxBase) const
   {
     TRACE_SUBSET (this);
@@ -1381,7 +1426,7 @@
   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
 
   bool subset (hb_subset_context_t *c,
-               const VarStoreInstancer &instancer,
+               const ItemVarStoreInstancer &instancer,
                uint32_t varIdxBase) const
   {
     TRACE_SUBSET (this);
@@ -1440,7 +1485,7 @@
   void closurev1 (hb_colrv1_closure_context_t* c) const;
 
   bool subset (hb_subset_context_t *c,
-               const VarStoreInstancer &instancer) const
+               const ItemVarStoreInstancer &instancer) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (this);
@@ -1491,7 +1536,7 @@
     return_trace (c->check_struct (this));
   }
 
-  void get_clip_box (ClipBoxData &clip_box, const VarStoreInstancer &instancer HB_UNUSED) const
+  void get_clip_box (ClipBoxData &clip_box, const ItemVarStoreInstancer &instancer HB_UNUSED) const
   {
     clip_box.xMin = xMin;
     clip_box.yMin = yMin;
@@ -1500,7 +1545,7 @@
   }
 
   bool subset (hb_subset_context_t *c,
-               const VarStoreInstancer &instancer,
+               const ItemVarStoreInstancer &instancer,
                uint32_t varIdxBase) const
   {
     TRACE_SUBSET (this);
@@ -1533,7 +1578,7 @@
 
 struct ClipBoxFormat2 : Variable<ClipBoxFormat1>
 {
-  void get_clip_box (ClipBoxData &clip_box, const VarStoreInstancer &instancer) const
+  void get_clip_box (ClipBoxData &clip_box, const ItemVarStoreInstancer &instancer) const
   {
     value.get_clip_box(clip_box, instancer);
     if (instancer)
@@ -1544,12 +1589,15 @@
       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 VarStoreInstancer &instancer) const
+               const ItemVarStoreInstancer &instancer) const
   {
     TRACE_SUBSET (this);
     switch (u.format) {
@@ -1559,6 +1607,14 @@
     }
   }
 
+  void closurev1 (hb_colrv1_closure_context_t* c) const
+  {
+    switch (u.format) {
+    case 2: u.format2.closurev1 (c);
+    default:return;
+    }
+  }
+
   template <typename context_t, typename ...Ts>
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
@@ -1572,7 +1628,7 @@
   }
 
   bool get_extents (hb_glyph_extents_t *extents,
-                    const VarStoreInstancer &instancer) const
+                    const ItemVarStoreInstancer &instancer) const
   {
     ClipBoxData clip_box;
     switch (u.format) {
@@ -1606,9 +1662,15 @@
   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 VarStoreInstancer &instancer) const
+               const ItemVarStoreInstancer &instancer) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (*this);
@@ -1625,7 +1687,7 @@
 
   bool get_extents (hb_glyph_extents_t *extents,
 		    const void *base,
-		    const VarStoreInstancer &instancer) const
+		    const ItemVarStoreInstancer &instancer) const
   {
     return (base+clipBox).get_extents (extents, instancer);
   }
@@ -1642,7 +1704,7 @@
 struct ClipList
 {
   unsigned serialize_clip_records (hb_subset_context_t *c,
-                                   const VarStoreInstancer &instancer,
+                                   const ItemVarStoreInstancer &instancer,
                                    const hb_set_t& gids,
                                    const hb_map_t& gid_offset_map) const
   {
@@ -1695,7 +1757,7 @@
   }
 
   bool subset (hb_subset_context_t *c,
-               const VarStoreInstancer &instancer) const
+               const ItemVarStoreInstancer &instancer) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->start_embed (*this);
@@ -1735,7 +1797,7 @@
   bool
   get_extents (hb_codepoint_t gid,
 	       hb_glyph_extents_t *extents,
-	       const VarStoreInstancer &instancer) const
+	       const ItemVarStoreInstancer &instancer) const
   {
     auto *rec = clips.as_array ().bsearch (gid);
     if (rec)
@@ -1855,7 +1917,7 @@
 
   bool serialize (hb_serialize_context_t *s, const hb_map_t* glyph_map,
                   const void* src_base, hb_subset_context_t *c,
-                  const VarStoreInstancer &instancer) const
+                  const ItemVarStoreInstancer &instancer) const
   {
     TRACE_SERIALIZE (this);
     auto *out = s->embed (this);
@@ -1884,7 +1946,7 @@
 struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord>
 {
   bool subset (hb_subset_context_t *c,
-               const VarStoreInstancer &instancer) const
+               const ItemVarStoreInstancer &instancer) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->start_embed (this);
@@ -1916,7 +1978,7 @@
   { return this+(*this)[i]; }
 
   bool subset (hb_subset_context_t *c,
-               const VarStoreInstancer &instancer) const
+               const ItemVarStoreInstancer &instancer) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->start_embed (this);
@@ -1941,6 +2003,76 @@
   }
 };
 
+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<const uint32_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<uint32_t> output_map;
+};
+
 struct COLR
 {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR;
@@ -1948,10 +2080,11 @@
   bool has_v0_data () const { return numBaseGlyphs; }
   bool has_v1_data () const
   {
-    if (version == 1)
-      return (this+baseGlyphList).len > 0;
+    if (version != 1)
+      return false;
+    hb_barrier ();
 
-    return false;
+    return (this+baseGlyphList).len > 0;
   }
 
   unsigned int get_glyph_layers (hb_codepoint_t       glyph,
@@ -1991,8 +2124,22 @@
 
     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); }
+                        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> colr;
@@ -2029,12 +2176,16 @@
 
   void closure_forV1 (hb_set_t *glyphset,
                       hb_set_t *layer_indices,
-                      hb_set_t *palette_indices) const
+                      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);
+    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 ())
@@ -2046,6 +2197,22 @@
       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
@@ -2054,14 +2221,28 @@
   const BaseGlyphList& get_baseglyphList () const
   { return (this+baseGlyphList); }
 
+  bool has_var_store () const
+  { return version >= 1 && varStore != 0; }
+
+  bool has_delta_set_index_map () const
+  { return version >= 1 && varIdxMap != 0; }
+
+  const DeltaSetIndexMap &get_delta_set_index_map () const
+  { return (version == 0 || varIdxMap == 0) ? Null (DeltaSetIndexMap) : this+varIdxMap; }
+
+  const ItemVariationStore &get_var_store () const
+  { return (version == 0 || varStore == 0) ? Null (ItemVariationStore) : this+varStore; }
+
   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 ||
-		   (version == 1 &&
+		   (hb_barrier () &&
+		    version == 1 &&
 		    baseGlyphList.sanitize (c, this) &&
 		    layerList.sanitize (c, this) &&
 		    clipList.sanitize (c, this) &&
@@ -2127,6 +2308,88 @@
     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);
+
+      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);
+
+      /* if varstore is optimized, update colrv1_new_deltaset_idx_varidx_map in
+       * subset plan */
+      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);
@@ -2195,34 +2458,28 @@
     auto *colr_prime = c->serializer->start_embed<COLR> ();
     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));
+    if (version == 0 || downgrade_to_V0 (glyphset))
+    return_trace (colr_prime->serialize_V0 (c->serializer, 0, base_it, layer_it));
 
-    auto snap = c->serializer->snapshot ();
+    //start version 1
     if (!c->serializer->allocate_size<void> (5 * HBUINT32::static_size)) return_trace (false);
+    if (!colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it)) return_trace (false);
 
-    VarStoreInstancer instancer (varStore ? &(this+varStore) : nullptr,
+    /* subset ItemVariationStore first, cause varidx_map needs to be updated
+     * after instancing */
+    if (!subset_varstore (c, colr_prime)) return_trace (false);
+
+    ItemVarStoreInstancer instancer (varStore ? &(this+varStore) : nullptr,
 	                         varIdxMap ? &(this+varIdxMap) : nullptr,
 	                         c->plan->normalized_coords.as_array ());
 
     if (!colr_prime->baseGlyphList.serialize_subset (c, baseGlyphList, this, instancer))
-    {
-      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);
+      return_trace (false);
 
     colr_prime->layerList.serialize_subset (c, layerList, this, instancer);
     colr_prime->clipList.serialize_subset (c, clipList, this, instancer);
-    if (!varStore || c->plan->all_axes_pinned)
-      return_trace (true);
 
-    colr_prime->varIdxMap.serialize_copy (c->serializer, varIdxMap, this);
-    colr_prime->varStore.serialize_copy (c->serializer, varStore, this);
-    return_trace (true);
+    return_trace (subset_delta_set_index_map (c, colr_prime));
   }
 
   const Paint *get_base_glyph_paint (hb_codepoint_t glyph) const
@@ -2245,7 +2502,7 @@
     if (version != 1)
       return false;
 
-    VarStoreInstancer instancer (&(this+varStore),
+    ItemVarStoreInstancer instancer (&(this+varStore),
 				 &(this+varIdxMap),
 				 hb_array (font->coords, font->num_coords));
 
@@ -2284,6 +2541,8 @@
   {
     if (version == 1)
     {
+      hb_barrier ();
+
       const Paint *paint = get_base_glyph_paint (glyph);
 
       return paint != nullptr;
@@ -2294,7 +2553,7 @@
 
   bool get_clip (hb_codepoint_t glyph,
 		 hb_glyph_extents_t *extents,
-		 const VarStoreInstancer instancer) const
+		 const ItemVarStoreInstancer instancer) const
   {
     return (this+clipList).get_extents (glyph,
 					extents,
@@ -2305,7 +2564,7 @@
   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
   {
-    VarStoreInstancer instancer (&(this+varStore),
+    ItemVarStoreInstancer instancer (&(this+varStore),
 	                         &(this+varIdxMap),
 	                         hb_array (font->coords, font->num_coords));
     hb_paint_context_t c (this, funcs, data, font, palette_index, foreground, instancer);
@@ -2313,12 +2572,14 @@
 
     if (version == 1)
     {
+      hb_barrier ();
+
       const Paint *paint = get_base_glyph_paint (glyph);
       if (paint)
       {
         // COLRv1 glyph
 
-	VarStoreInstancer instancer (&(this+varStore),
+	ItemVarStoreInstancer instancer (&(this+varStore),
 				     &(this+varIdxMap),
 				     hb_array (font->coords, font->num_coords));
 
@@ -2404,7 +2665,7 @@
   Offset32To<LayerList>			layerList;
   Offset32To<ClipList>			clipList;   // Offset to ClipList table (may be NULL)
   Offset32To<DeltaSetIndexMap>		varIdxMap;  // Offset to DeltaSetIndexMap table (may be NULL)
-  Offset32To<VariationStore>		varStore;
+  Offset32To<ItemVariationStore>	varStore;
   public:
   DEFINE_SIZE_MIN (14);
 };
diff --git a/src/OT/Color/COLR/colrv1-closure.hh b/src/OT/Color/COLR/colrv1-closure.hh
index 705863d..9ed0aa5 100644
--- a/src/OT/Color/COLR/colrv1-closure.hh
+++ b/src/OT/Color/COLR/colrv1-closure.hh
@@ -66,34 +66,64 @@
 
 template <template<typename> class Var>
 HB_INTERNAL void PaintTransform<Var>::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
 {
diff --git a/src/OT/Color/CPAL/CPAL.hh b/src/OT/Color/CPAL/CPAL.hh
index c07716c..2821334 100644
--- a/src/OT/Color/CPAL/CPAL.hh
+++ b/src/OT/Color/CPAL/CPAL.hh
@@ -214,13 +214,17 @@
                          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<CPALV1Tail> (*this);
   }
 
@@ -312,7 +316,10 @@
       return_trace (false);
 
     if (version == 1)
+    {
+      hb_barrier ();
       return_trace (v1 ().serialize (c->serializer, numPalettes, numColors, this, color_index_map));
+    }
 
     return_trace (true);
   }
@@ -321,6 +328,7 @@
   {
     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)));
diff --git a/src/OT/Color/sbix/sbix.hh b/src/OT/Color/sbix/sbix.hh
index ce8693c..51ae1a9 100644
--- a/src/OT/Color/sbix/sbix.hh
+++ b/src/OT/Color/sbix/sbix.hh
@@ -368,6 +368,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (likely (c->check_struct (this) &&
+			  hb_barrier () &&
 			  version >= 1 &&
 			  strikes.sanitize (c, this)));
   }
diff --git a/src/OT/Color/svg/svg.hh b/src/OT/Color/svg/svg.hh
index c7d91b8..2e1f935 100644
--- a/src/OT/Color/svg/svg.hh
+++ b/src/OT/Color/svg/svg.hh
@@ -56,6 +56,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
+		  hb_barrier () &&
 		  svgDoc.sanitize (c, base, svgDocLength));
   }
 
diff --git a/src/OT/Layout/Common/Coverage.hh b/src/OT/Layout/Common/Coverage.hh
index 25056c9..344e87a 100644
--- a/src/OT/Layout/Common/Coverage.hh
+++ b/src/OT/Layout/Common/Coverage.hh
@@ -64,6 +64,7 @@
   {
     TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return_trace (false);
+    hb_barrier ();
     switch (u.format)
     {
     case 1: return_trace (u.format1.sanitize (c));
diff --git a/src/OT/Layout/GDEF/GDEF.hh b/src/OT/Layout/GDEF/GDEF.hh
index dd025c1..45baeb4 100644
--- a/src/OT/Layout/GDEF/GDEF.hh
+++ b/src/OT/Layout/GDEF/GDEF.hh
@@ -189,7 +189,7 @@
   friend struct CaretValue;
 
   hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction,
-				 const VariationStore &var_store) const
+				 const ItemVariationStore &var_store) const
   {
     return HB_DIRECTION_IS_HORIZONTAL (direction) ?
 	   font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) :
@@ -251,7 +251,7 @@
   hb_position_t get_caret_value (hb_font_t *font,
 				 hb_direction_t direction,
 				 hb_codepoint_t glyph_id,
-				 const VariationStore &var_store) const
+				 const ItemVariationStore &var_store) const
   {
     switch (u.format) {
     case 1: return u.format1.get_caret_value (font, direction);
@@ -291,6 +291,7 @@
   {
     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));
@@ -315,7 +316,7 @@
   unsigned get_lig_carets (hb_font_t            *font,
 			   hb_direction_t        direction,
 			   hb_codepoint_t        glyph_id,
-			   const VariationStore &var_store,
+			   const ItemVariationStore &var_store,
 			   unsigned              start_offset,
 			   unsigned             *caret_count /* IN/OUT */,
 			   hb_position_t        *caret_array /* OUT */) const
@@ -371,7 +372,7 @@
   unsigned int get_lig_carets (hb_font_t *font,
 			       hb_direction_t direction,
 			       hb_codepoint_t glyph_id,
-			       const VariationStore &var_store,
+			       const ItemVariationStore &var_store,
 			       unsigned int start_offset,
 			       unsigned int *caret_count /* IN/OUT */,
 			       hb_position_t *caret_array /* OUT */) const
@@ -441,6 +442,20 @@
   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 <typename set_t>
   void collect_coverage (hb_vector_t<set_t> &sets) const
   {
@@ -461,6 +476,7 @@
     bool ret = true;
     for (const Offset32To<Coverage>& offset : coverage.iter ())
     {
+      auto snap = c->serializer->snapshot ();
       auto *o = out->coverage.serialize_append (c->serializer);
       if (unlikely (!o))
       {
@@ -468,11 +484,17 @@
 	break;
       }
 
-      //not using o->serialize_subset (c, offset, this, out) here because
-      //OTS doesn't allow null offset.
-      //See issue: https://github.com/khaledhosny/ots/issues/172
+      //skip empty coverage
       c->serializer->push ();
-      c->dispatch (this+offset);
+      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 ());
     }
 
@@ -513,6 +535,15 @@
     }
   }
 
+  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);
@@ -526,6 +557,7 @@
   {
     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);
@@ -577,7 +609,7 @@
 					 * definitions--from beginning of GDEF
 					 * header (may be NULL).  Introduced
 					 * in version 0x00010002. */
-  Offset32To<VariationStore>
+  Offset32To<ItemVariationStore>
 		varStore;		/* Offset to the table of Item Variation
 					 * Store--from beginning of GDEF
 					 * header (may be NULL).  Introduced
@@ -600,6 +632,7 @@
 		  attachList.sanitize (c, this) &&
 		  ligCaretList.sanitize (c, this) &&
 		  markAttachClassDef.sanitize (c, this) &&
+		  hb_barrier () &&
 		  (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
 		  (version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
   }
@@ -627,23 +660,23 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    auto *out = c->serializer->embed (*this);
-    if (unlikely (!out)) return_trace (false);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
 
-    bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
-    bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
-    bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
-    bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
-
-    bool subset_markglyphsetsdef = false;
-    if (version.to_int () >= 0x00010002u)
-    {
-      subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
-    }
+    // 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 && !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)
     {
+      if (unlikely (!c->serializer->embed (varStore))) return_trace (false);
       if (c->plan->all_axes_pinned)
         out->varStore = 0;
       else if (c->plan->normalized_coords)
@@ -652,27 +685,56 @@
         {
           item_variations_t item_vars;
           if (item_vars.instantiate (this+varStore, c->plan, true, true,
-                                     c->plan->gdef_varstore_inner_maps.as_array ()))
+                                     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)
+    {
+      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;
+      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 ||
@@ -709,6 +771,7 @@
   {
     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
@@ -839,14 +902,14 @@
     default: return false;
     }
   }
-  const VariationStore &get_var_store () const
+  const ItemVariationStore &get_var_store () const
   {
     switch (u.version.major) {
-    case 1: return u.version.to_int () >= 0x00010003u ? this+u.version1.varStore : Null(VariationStore);
+    case 1: return u.version.to_int () >= 0x00010003u ? this+u.version1.varStore : Null(ItemVariationStore);
 #ifndef HB_NO_BEYOND_64K
     case 2: return this+u.version2.varStore;
 #endif
-    default: return Null(VariationStore);
+    default: return Null(ItemVariationStore);
     }
   }
 
@@ -959,47 +1022,6 @@
   void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
   { get_lig_caret_list ().collect_variation_indices (c); }
 
-  void remap_layout_variation_indices (const hb_set_t *layout_variation_indices,
-				       const hb_vector_t<int>& normalized_coords,
-				       bool calculate_delta, /* not pinned at default */
-				       bool no_variations, /* all axes pinned */
-				       hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map /* OUT */) const
-  {
-    if (!has_var_store ()) return;
-    const VariationStore &var_store = get_var_store ();
-    float *store_cache = var_store.create_cache ();
-    
-    unsigned new_major = 0, new_minor = 0;
-    unsigned last_major = (layout_variation_indices->get_min ()) >> 16;
-    for (unsigned idx : layout_variation_indices->iter ())
-    {
-      int delta = 0;
-      if (calculate_delta)
-        delta = roundf (var_store.get_delta (idx, normalized_coords.arrayZ,
-                                             normalized_coords.length, store_cache));
-
-      if (no_variations)
-      {
-        layout_variation_idx_delta_map->set (idx, hb_pair_t<unsigned, int> (HB_OT_LAYOUT_NO_VARIATIONS_INDEX, delta));
-        continue;
-      }
-
-      uint16_t major = idx >> 16;
-      if (major >= var_store.get_sub_table_count ()) break;
-      if (major != last_major)
-      {
-	new_minor = 0;
-	++new_major;
-      }
-
-      unsigned new_idx = (new_major << 16) + new_minor;
-      layout_variation_idx_delta_map->set (idx, hb_pair_t<unsigned, int> (new_idx, delta));
-      ++new_minor;
-      last_major = major;
-    }
-    var_store.destroy_cache (store_cache);
-  }
-
   protected:
   union {
   FixedVersion<>		version;	/* Version identifier */
diff --git a/src/OT/Layout/GPOS/Anchor.hh b/src/OT/Layout/GPOS/Anchor.hh
index 49e76e7..7802e39 100644
--- a/src/OT/Layout/GPOS/Anchor.hh
+++ b/src/OT/Layout/GPOS/Anchor.hh
@@ -25,6 +25,7 @@
   {
     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/src/OT/Layout/GPOS/AnchorFormat3.hh b/src/OT/Layout/GPOS/AnchorFormat3.hh
index 56eda4a..b542265 100644
--- a/src/OT/Layout/GPOS/AnchorFormat3.hh
+++ b/src/OT/Layout/GPOS/AnchorFormat3.hh
@@ -38,9 +38,15 @@
     *y = font->em_fscale_y (yCoordinate);
 
     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) && 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
diff --git a/src/OT/Layout/GPOS/AnchorMatrix.hh b/src/OT/Layout/GPOS/AnchorMatrix.hh
index 37ba791..2557e9a 100644
--- a/src/OT/Layout/GPOS/AnchorMatrix.hh
+++ b/src/OT/Layout/GPOS/AnchorMatrix.hh
@@ -8,7 +8,7 @@
 struct AnchorMatrix
 {
   HBUINT16      rows;                   /* Number of rows */
-  UnsizedArrayOf<Offset16To<Anchor>>
+  UnsizedArrayOf<Offset16To<Anchor, AnchorMatrix>>
                 matrixZ;                /* Matrix of offsets to Anchor tables--
                                          * from beginning of AnchorMatrix table */
   public:
@@ -18,6 +18,7 @@
   {
     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);
@@ -25,6 +26,7 @@
     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);
@@ -38,6 +40,7 @@
     if (unlikely (row >= rows || col >= cols)) return Null (Anchor);
     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;
   }
@@ -65,15 +68,14 @@
     if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
 
     out->rows = num_rows;
-    bool ret = false;
     for (const unsigned i : index_iter)
     {
       auto *offset = c->serializer->embed (matrixZ[i]);
       if (!offset) return_trace (false);
-      ret |= offset->serialize_subset (c, matrixZ[i], this);
+      offset->serialize_subset (c, matrixZ[i], this);
     }
 
-    return_trace (ret);
+    return_trace (true);
   }
 };
 
diff --git a/src/OT/Layout/GPOS/Common.hh b/src/OT/Layout/GPOS/Common.hh
index 4081974..696d25d 100644
--- a/src/OT/Layout/GPOS/Common.hh
+++ b/src/OT/Layout/GPOS/Common.hh
@@ -23,7 +23,7 @@
                                  const SrcLookup *src,
                                  Iterator it,
                                  const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
-                                 bool all_axes_pinned);
+                                 unsigned new_format);
 
 
 }
diff --git a/src/OT/Layout/GPOS/CursivePosFormat1.hh b/src/OT/Layout/GPOS/CursivePosFormat1.hh
index 7c42c3f..6b019ac 100644
--- a/src/OT/Layout/GPOS/CursivePosFormat1.hh
+++ b/src/OT/Layout/GPOS/CursivePosFormat1.hh
@@ -11,21 +11,21 @@
 {
   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);
   }
 
   bool subset (hb_subset_context_t *c,
-	       const void *src_base) const
+	       const struct CursivePosFormat1 *src_base) const
   {
     TRACE_SERIALIZE (this);
     auto *out = c->serializer->embed (this);
@@ -38,11 +38,11 @@
   }
 
   protected:
-  Offset16To<Anchor>
+  Offset16To<Anchor, struct CursivePosFormat1>
                 entryAnchor;            /* Offset to EntryAnchor table--from
                                          * beginning of CursivePos
                                          * subtable--may be NULL */
-  Offset16To<Anchor>
+  Offset16To<Anchor, struct CursivePosFormat1>
                 exitAnchor;             /* Offset to ExitAnchor table--from
                                          * beginning of CursivePos
                                          * subtable--may be NULL */
@@ -128,6 +128,7 @@
     const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage  (buffer->cur().codepoint)];
     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_fast (buffer->idx);
@@ -145,6 +146,7 @@
       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;
@@ -262,7 +264,7 @@
             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;
diff --git a/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh b/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh
index 70cf071..57eb782 100644
--- a/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh
+++ b/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh
@@ -42,6 +42,7 @@
                   mark1Coverage.sanitize (c, this) &&
                   mark2Coverage.sanitize (c, this) &&
                   mark1Array.sanitize (c, this) &&
+		  hb_barrier () &&
                   mark2Array.sanitize (c, this, (unsigned int) classCount));
   }
 
diff --git a/src/OT/Layout/GPOS/PairPosFormat1.hh b/src/OT/Layout/GPOS/PairPosFormat1.hh
index e4a2006..ac2774a 100644
--- a/src/OT/Layout/GPOS/PairPosFormat1.hh
+++ b/src/OT/Layout/GPOS/PairPosFormat1.hh
@@ -36,6 +36,7 @@
     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 ();
@@ -131,20 +132,33 @@
     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<unsigned, unsigned> newFormats = compute_effective_value_formats (glyphset);
-      out->valueFormat[0] = newFormats.first;
-      out->valueFormat[1] = newFormats.second;
-    }
 
-    if (c->plan->all_axes_pinned)
+    hb_pair_t<unsigned, unsigned> newFormats = hb_pair (valueFormat[0], valueFormat[1]);
+
+    if (c->plan->normalized_coords)
     {
-      out->valueFormat[0] = out->valueFormat[0].drop_device_table_flags ();
-      out->valueFormat[1] = out->valueFormat[1].drop_device_table_flags ();
+      /* 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);
     }
+    /* 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;
+      newFormats = compute_effective_value_formats (glyphset, strip, true);
+    }
+    
+    out->valueFormat[0] = newFormats.first;
+    out->valueFormat[1] = newFormats.second;
 
     hb_sorted_vector_t<hb_codepoint_t> new_coverage;
 
@@ -175,7 +189,9 @@
   }
 
 
-  hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset) const
+  hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset,
+                                                                 bool strip_hints, bool strip_empty,
+                                                                 const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map = nullptr) const
   {
     unsigned record_size = PairSet::get_size (valueFormat);
 
@@ -195,8 +211,8 @@
       {
         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<const PairValueRecord> (record, record_size);
       }
diff --git a/src/OT/Layout/GPOS/PairPosFormat2.hh b/src/OT/Layout/GPOS/PairPosFormat2.hh
index 4adb1ef..9c805b3 100644
--- a/src/OT/Layout/GPOS/PairPosFormat2.hh
+++ b/src/OT/Layout/GPOS/PairPosFormat2.hh
@@ -8,7 +8,7 @@
 namespace GPOS_impl {
 
 template <typename Types>
-struct PairPosFormat2_4
+struct PairPosFormat2_4 : ValueBase
 {
   protected:
   HBUINT16      format;                 /* Format identifier--format = 2 */
@@ -287,18 +287,31 @@
     unsigned len2 = valueFormat2.get_len ();
 
     hb_pair_t<unsigned, unsigned> newFormats = hb_pair (valueFormat1, valueFormat2);
-    if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
-      newFormats = compute_effective_value_formats (klass1_map, klass2_map);
+
+    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)
+    {
+      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;
 
-    if (c->plan->all_axes_pinned)
-    {
-      out->valueFormat1 = out->valueFormat1.drop_device_table_flags ();
-      out->valueFormat2 = out->valueFormat2.drop_device_table_flags ();
-    }
-
     unsigned total_len = len1 + len2;
     hb_vector_t<unsigned> class2_idxs (+ hb_range ((unsigned) class2Count) | hb_filter (klass2_map));
     for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map))
@@ -311,22 +324,15 @@
       }
     }
 
-    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<unsigned, unsigned> 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<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map = nullptr) const
   {
     unsigned len1 = valueFormat1.get_len ();
     unsigned len2 = valueFormat2.get_len ();
@@ -340,8 +346,8 @@
       for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
       {
         unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * record_size;
-        format1 = format1 | valueFormat1.get_effective_format (&values[idx]);
-        format2 = format2 | valueFormat2.get_effective_format (&values[idx + len1]);
+        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)
diff --git a/src/OT/Layout/GPOS/PairSet.hh b/src/OT/Layout/GPOS/PairSet.hh
index db301bb..5560fab 100644
--- a/src/OT/Layout/GPOS/PairSet.hh
+++ b/src/OT/Layout/GPOS/PairSet.hh
@@ -9,7 +9,7 @@
 
 
 template <typename Types>
-struct PairSet
+struct PairSet : ValueBase
 {
   template <typename Types2>
   friend struct PairPosFormat1_3;
@@ -45,10 +45,12 @@
   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,
                           closure->stride))) return_trace (false);
+    hb_barrier ();
 
     unsigned int count = len;
     const PairValueRecord *record = &firstPairValueRecord;
diff --git a/src/OT/Layout/GPOS/PairValueRecord.hh b/src/OT/Layout/GPOS/PairValueRecord.hh
index 72bf0e9..d00618b 100644
--- a/src/OT/Layout/GPOS/PairValueRecord.hh
+++ b/src/OT/Layout/GPOS/PairValueRecord.hh
@@ -29,7 +29,7 @@
 
   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 @@
 
   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/src/OT/Layout/GPOS/SinglePos.hh b/src/OT/Layout/GPOS/SinglePos.hh
index 3af6c49..a0243a2 100644
--- a/src/OT/Layout/GPOS/SinglePos.hh
+++ b/src/OT/Layout/GPOS/SinglePos.hh
@@ -39,14 +39,12 @@
                   const SrcLookup* src,
                   Iterator glyph_val_iter_pairs,
                   const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
-                  bool all_axes_pinned)
+                  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);
@@ -89,8 +87,8 @@
                      const SrcLookup *src,
                      Iterator it,
                      const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
-                     bool all_axes_pinned)
-{ c->start_embed<SinglePos> ()->serialize (c, src, it, layout_variation_idx_delta_map, all_axes_pinned); }
+                     unsigned new_format)
+{ c->start_embed<SinglePos> ()->serialize (c, src, it, layout_variation_idx_delta_map, new_format); }
 
 
 }
diff --git a/src/OT/Layout/GPOS/SinglePosFormat1.hh b/src/OT/Layout/GPOS/SinglePosFormat1.hh
index dff1f73..b2d151d 100644
--- a/src/OT/Layout/GPOS/SinglePosFormat1.hh
+++ b/src/OT/Layout/GPOS/SinglePosFormat1.hh
@@ -8,7 +8,7 @@
 namespace Layout {
 namespace GPOS_impl {
 
-struct SinglePosFormat1
+struct SinglePosFormat1 : ValueBase
 {
   protected:
   HBUINT16      format;                 /* Format identifier--format = 1 */
@@ -28,6 +28,7 @@
     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
@@ -146,6 +147,30 @@
     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)
@@ -153,7 +178,7 @@
     ;
 
     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/src/OT/Layout/GPOS/SinglePosFormat2.hh b/src/OT/Layout/GPOS/SinglePosFormat2.hh
index 168ad3b..ae4a5ed 100644
--- a/src/OT/Layout/GPOS/SinglePosFormat2.hh
+++ b/src/OT/Layout/GPOS/SinglePosFormat2.hh
@@ -7,7 +7,7 @@
 namespace Layout {
 namespace GPOS_impl {
 
-struct SinglePosFormat2
+struct SinglePosFormat2 : ValueBase
 {
   protected:
   HBUINT16      format;                 /* Format identifier--format = 2 */
@@ -143,6 +143,37 @@
     coverage.serialize_serialize (c, glyphs);
   }
 
+  template<typename Iterator,
+      hb_requires (hb_is_iterator (Iterator))>
+  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<unsigned, hb_pair_t<unsigned, int>> *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);
@@ -163,8 +194,13 @@
                               })
     ;
 
+    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/src/OT/Layout/GPOS/ValueFormat.hh b/src/OT/Layout/GPOS/ValueFormat.hh
index 461a13d..9442cc1 100644
--- a/src/OT/Layout/GPOS/ValueFormat.hh
+++ b/src/OT/Layout/GPOS/ValueFormat.hh
@@ -9,6 +9,8 @@
 
 typedef HBUINT16 Value;
 
+struct ValueBase {}; // Dummy base class tag for OffsetTo<Value> bases.
+
 typedef UnsizedArrayOf<Value> ValueRecord;
 
 struct ValueFormat : HBUINT16
@@ -78,7 +80,7 @@
   }
 
   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,7 +116,7 @@
 
     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 */
@@ -142,11 +144,29 @@
     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<unsigned, hb_pair_t<unsigned, int>> *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;
@@ -154,18 +174,19 @@
 
   template<typename Iterator,
       hb_requires (hb_is_iterator (Iterator))>
-  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<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const {
     unsigned int new_format = 0;
 
     for (const hb_array_t<const Value>& 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<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const
   {
@@ -217,7 +238,7 @@
   }
 
   void collect_variation_indices (hb_collect_variation_indices_context_t *c,
-                                  const void *base,
+                                  const ValueBase *base,
                                   const hb_array_t<const Value>& values) const
   {
     unsigned format = *this;
@@ -251,17 +272,8 @@
     }
   }
 
-  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;
 
@@ -278,17 +290,17 @@
     return true;
   }
 
-  static inline Offset16To<Device>& get_device (Value* value)
+  static inline Offset16To<Device, ValueBase>& get_device (Value* value)
   {
-    return *static_cast<Offset16To<Device> *> (value);
+    return *static_cast<Offset16To<Device, ValueBase> *> (value);
   }
-  static inline const Offset16To<Device>& get_device (const Value* value)
+  static inline const Offset16To<Device, ValueBase>& get_device (const Value* value)
   {
-    return *static_cast<const Offset16To<Device> *> (value);
+    return *static_cast<const Offset16To<Device, ValueBase> *> (value);
   }
   static inline const Device& get_device (const Value* value,
 					  bool *worked,
-					  const void *base,
+					  const ValueBase *base,
 					  hb_sanitize_context_t &c)
   {
     if (worked) *worked |= bool (*value);
@@ -296,12 +308,13 @@
 
     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<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const
   {
@@ -313,7 +326,8 @@
     *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<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
                     unsigned int new_format, Flags flag) const
@@ -354,7 +368,7 @@
     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);
 
@@ -366,7 +380,7 @@
     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 size = get_size ();
@@ -376,11 +390,12 @@
     if (c->lazy_some_gpos)
       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);
 
@@ -403,6 +418,20 @@
     *format = *format & ~flag;
   }
 
+  void update_var_flag (const Value* value, Flags flag,
+                        unsigned int* format, const ValueBase *base,
+                        const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const
+  {
+    if (*value)
+    {
+      unsigned varidx = (base + get_device (value)).get_variation_index ();
+      hb_pair_t<unsigned, int> *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/src/OT/Layout/GSUB/Ligature.hh b/src/OT/Layout/GSUB/Ligature.hh
index 402ed12..e0ec82a 100644
--- a/src/OT/Layout/GSUB/Ligature.hh
+++ b/src/OT/Layout/GSUB/Ligature.hh
@@ -90,8 +90,17 @@
 
     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],
@@ -102,6 +111,8 @@
                               &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);
     }
 
@@ -145,6 +156,8 @@
 			  pos);
     }
 
+    if (match_positions != match_positions_stack)
+      hb_free (match_positions);
     return_trace (true);
   }
 
diff --git a/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh b/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh
index 916fa28..ec374f2 100644
--- a/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh
+++ b/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh
@@ -33,9 +33,11 @@
     TRACE_SANITIZE (this);
     if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
       return_trace (false);
+    hb_barrier ();
     const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
     if (!lookahead.sanitize (c, this))
       return_trace (false);
+    hb_barrier ();
     const auto &substitute = StructAfter<decltype (substituteX)> (lookahead);
     return_trace (substitute.sanitize (c));
   }
@@ -109,12 +111,12 @@
   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<decltype (lookaheadX)> (backtrack);
     const auto &substitute = StructAfter<decltype (substituteX)> (lookahead);
 
diff --git a/src/OT/Layout/types.hh b/src/OT/Layout/types.hh
index 6a43403..3840db0 100644
--- a/src/OT/Layout/types.hh
+++ b/src/OT/Layout/types.hh
@@ -38,8 +38,8 @@
   using HBUINT = HBUINT16;
   using HBGlyphID = HBGlyphID16;
   using Offset = Offset16;
-  template <typename Type, bool has_null=true>
-  using OffsetTo = OT::Offset16To<Type, has_null>;
+  template <typename Type, typename BaseType=void, bool has_null=true>
+  using OffsetTo = OT::Offset16To<Type, BaseType, has_null>;
   template <typename Type>
   using ArrayOf = OT::Array16Of<Type>;
   template <typename Type>
@@ -52,8 +52,8 @@
   using HBUINT = HBUINT24;
   using HBGlyphID = HBGlyphID24;
   using Offset = Offset24;
-  template <typename Type, bool has_null=true>
-  using OffsetTo = OT::Offset24To<Type, has_null>;
+  template <typename Type, typename BaseType=void, bool has_null=true>
+  using OffsetTo = OT::Offset24To<Type, BaseType, has_null>;
   template <typename Type>
   using ArrayOf = OT::Array24Of<Type>;
   template <typename Type>
diff --git a/src/OT/glyf/CompositeGlyph.hh b/src/OT/glyf/CompositeGlyph.hh
index 60858a5..5c0ecd5 100644
--- a/src/OT/glyf/CompositeGlyph.hh
+++ b/src/OT/glyf/CompositeGlyph.hh
@@ -240,7 +240,8 @@
     }
     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;
diff --git a/src/OT/glyf/Glyph.hh b/src/OT/glyf/Glyph.hh
index 5ea6119..69a0b62 100644
--- a/src/OT/glyf/Glyph.hh
+++ b/src/OT/glyf/Glyph.hh
@@ -103,6 +103,9 @@
     }
   }
 
+  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
   {
diff --git a/src/OT/name/name.hh b/src/OT/name/name.hh
index c8de101..e2a25d4 100644
--- a/src/OT/name/name.hh
+++ b/src/OT/name/name.hh
@@ -242,7 +242,9 @@
   bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && offset.sanitize (c, base, length));
+    return_trace (c->check_struct (this) &&
+		  hb_barrier () &&
+		  offset.sanitize (c, base, length));
   }
 
   HBUINT16	platformID;	/* Platform ID. */
@@ -465,6 +467,7 @@
   {
     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) &&
diff --git a/src/check-c-linkage-decls.py b/src/check-c-linkage-decls.py
index fe18eda..27f5639 100755
--- a/src/check-c-linkage-decls.py
+++ b/src/check-c-linkage-decls.py
@@ -14,6 +14,7 @@
 
 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/src/fix_get_types.py b/src/fix_get_types.py
index 208b9df..64d8ce5 100755
--- a/src/fix_get_types.py
+++ b/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/src/gen-def.py b/src/gen-def.py
index c34976a..6011817 100755
--- a/src/gen-def.py
+++ b/src/gen-def.py
@@ -22,7 +22,6 @@
 """hb_shape_justify
 hb_subset_repack_or_fail
 hb_subset_input_override_name_table
-hb_subset_input_set_axis_range
 """.splitlines ()
 	symbols = [x for x in symbols if x not in experimental_symbols]
 symbols = "\n".join (symbols)
diff --git a/src/gen-tag-table.py b/src/gen-tag-table.py
index 7e15c08..4769ee8 100755
--- a/src/gen-tag-table.py
+++ b/src/gen-tag-table.py
@@ -584,7 +584,7 @@
 						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
@@ -1127,9 +1127,10 @@
 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 +1171,8 @@
 			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:
@@ -1191,9 +1193,11 @@
 						'%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/src/gen-use-table.py b/src/gen-use-table.py
index 4e87b84..0012e5d 100755
--- a/src/gen-use-table.py
+++ b/src/gen-use-table.py
@@ -1,9 +1,6 @@
 #!/usr/bin/env python3
 # flake8: noqa: F821
 
-import logging
-logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO)
-
 """usage: ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt ArabicShaping.txt DerivedCoreProperties.txt UnicodeData.txt Blocks.txt Scripts.txt IndicSyllabicCategory-Additional.txt IndicPositionalCategory-Additional.txt
 
 Input files:
@@ -18,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:
diff --git a/src/graph/classdef-graph.hh b/src/graph/classdef-graph.hh
index c143288..da63788 100644
--- a/src/graph/classdef-graph.hh
+++ b/src/graph/classdef-graph.hh
@@ -39,6 +39,7 @@
     int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
     constexpr unsigned min_size = OT::ClassDefFormat1_3<SmallTypes>::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 @@
     int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
     constexpr unsigned min_size = OT::ClassDefFormat2_4<SmallTypes>::min_size;
     if (vertex_len < min_size) return false;
+    hb_barrier ();
     return vertex_len >= min_size + rangeRecord.get_size () - rangeRecord.len.get_size ();
   }
 };
@@ -114,6 +116,7 @@
   {
     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);
@@ -131,20 +134,23 @@
 
 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<typename It>
   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);
@@ -174,28 +180,54 @@
     }
   }
 
-  // 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
-  {
-    // Coverage takes 2 bytes per glyph worst case,
-    return 2 * glyphs_per_class.get (klass).get_population ();
+  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();
   }
 
-  // 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 size of coverage for all glyphs added via 'add_class_def_size'.
+  unsigned coverage_size () const
   {
-    // 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);
+    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);
+  }
+
+  // Compute the new size of the ClassDef table if all glyphs associated with 'klass' were added.
+  unsigned add_class_def_size (unsigned klass)
+  {
+    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 ()
@@ -211,9 +243,12 @@
   }
 
  private:
-  bool gids_consecutive;
   hb_hashmap_t<unsigned, unsigned> num_ranges_per_class;
   hb_hashmap_t<unsigned, hb_set_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/src/graph/coverage-graph.hh b/src/graph/coverage-graph.hh
index 4f44e07..61ca063 100644
--- a/src/graph/coverage-graph.hh
+++ b/src/graph/coverage-graph.hh
@@ -39,6 +39,7 @@
     int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
     constexpr unsigned min_size = OT::Layout::Common::CoverageFormat1_3<SmallTypes>::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 @@
     int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
     constexpr unsigned min_size = OT::Layout::Common::CoverageFormat2_4<SmallTypes>::min_size;
     if (vertex_len < min_size) return false;
+    hb_barrier ();
     return vertex_len >= min_size + rangeRecord.get_size () - rangeRecord.len.get_size ();
   }
 };
@@ -138,6 +140,7 @@
   {
     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);
diff --git a/src/graph/graph.hh b/src/graph/graph.hh
index 2b4e1b2..2a9d834 100644
--- a/src/graph/graph.hh
+++ b/src/graph/graph.hh
@@ -195,6 +195,15 @@
       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;
@@ -334,6 +343,16 @@
       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;
     }
@@ -567,6 +586,7 @@
     update_distances ();
 
     hb_priority_queue_t<int64_t> queue;
+    queue.alloc (vertices_.length);
     hb_vector_t<vertex_t> &sorted_graph = vertices_scratch_;
     if (unlikely (!check_success (sorted_graph.resize (vertices_.length)))) return;
     hb_vector_t<unsigned> id_map;
@@ -1022,6 +1042,11 @@
    * 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)
   {
@@ -1035,18 +1060,20 @@
    * 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.
@@ -1059,7 +1086,7 @@
                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++;
 
@@ -1075,6 +1102,62 @@
     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.
@@ -1370,6 +1453,7 @@
     vertices_.tail ().distance = 0;
 
     hb_priority_queue_t<int64_t> queue;
+    queue.alloc (count);
     queue.insert (0, vertices_.length - 1);
 
     hb_vector_t<bool> visited;
diff --git a/src/graph/gsubgpos-graph.hh b/src/graph/gsubgpos-graph.hh
index 12fcbdc..0f6d566 100644
--- a/src/graph/gsubgpos-graph.hh
+++ b/src/graph/gsubgpos-graph.hh
@@ -76,6 +76,7 @@
   {
     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 ();
   }
 
@@ -351,6 +352,7 @@
   {
     int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
     if (vertex_len < OT::LookupList<T>::min_size) return false;
+    hb_barrier ();
     return vertex_len >= OT::LookupList<T>::item_size * this->len;
   }
 };
@@ -364,6 +366,7 @@
     GSTAR* gstar = (GSTAR*) r.obj.head;
     if (!gstar || !gstar->sanitize (r))
       return nullptr;
+    hb_barrier ();
 
     return gstar;
   }
@@ -383,6 +386,7 @@
   {
     int64_t len = vertex.obj.tail - vertex.obj.head;
     if (len < OT::GSUBGPOS::min_size) return false;
+    hb_barrier ();
     return len >= get_size ();
   }
 
diff --git a/src/graph/markbasepos-graph.hh b/src/graph/markbasepos-graph.hh
index ae5ebd0..fb41661 100644
--- a/src/graph/markbasepos-graph.hh
+++ b/src/graph/markbasepos-graph.hh
@@ -40,6 +40,7 @@
   {
     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;
@@ -128,6 +129,7 @@
     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 ();
   }
@@ -495,6 +497,7 @@
   {
     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:
diff --git a/src/graph/pairpos-graph.hh b/src/graph/pairpos-graph.hh
index ad158cc..fd46861 100644
--- a/src/graph/pairpos-graph.hh
+++ b/src/graph/pairpos-graph.hh
@@ -42,6 +42,7 @@
     int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
     unsigned min_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::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 @@
     size_t vertex_len = vertex.table_size ();
     unsigned min_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size;
     if (vertex_len < min_size) return false;
+    hb_barrier ();
 
     const unsigned class1_count = class1Count;
     return vertex_len >=
@@ -245,8 +247,8 @@
     for (unsigned i = 0; i < class1_count; i++)
     {
       unsigned accumulated_delta = class1_record_size;
-      coverage_size += estimator.incremental_coverage_size (i);
-      class_def_1_size += estimator.incremental_class_def_size (i);
+      class_def_1_size = estimator.add_class_def_size (i);
+      coverage_size = estimator.coverage_size ();
       max_coverage_size = hb_max (max_coverage_size, coverage_size);
       max_class_def_1_size = hb_max (max_class_def_1_size, class_def_1_size);
 
@@ -278,8 +280,10 @@
         split_points.push (i);
         // split does not include i, so add the size for i when we reset the size counters.
         accumulated = base_size + accumulated_delta;
-        coverage_size = 4 + estimator.incremental_coverage_size (i);
-        class_def_1_size = 4 + estimator.incremental_class_def_size (i);
+
+        estimator.reset();
+        class_def_1_size = estimator.add_class_def_size(i);
+        coverage_size = estimator.coverage_size();
         visited.clear (); // node sharing isn't allowed between splits.
       }
     }
@@ -625,6 +629,7 @@
   {
     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:
diff --git a/src/graph/test-classdef-graph.cc b/src/graph/test-classdef-graph.cc
index 266be5e..2da9348 100644
--- a/src/graph/test-classdef-graph.cc
+++ b/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_codepoint_pair_t gid_and_class_t;
 typedef hb_vector_t<gid_and_class_t> gid_and_class_list_t;
 
+template<typename It>
+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<unsigned> 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<typename It>
+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<unsigned> 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<unsigned> klasses)
 {
-  graph::class_def_size_estimator_t estimator (list.iter ());
+  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;
+}
 
-  unsigned result = estimator.incremental_coverage_size (klass);
-  if (result != cov_expected)
-  {
-    printf ("FAIL: coverage expected size %u but was %u\n", cov_expected, result);
+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<unsigned> 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;
   }
 
-  result = estimator.incremental_class_def_size (klass);
-  if (result != class_def_expected)
+  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.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: class def expected size %u but was %u\n", class_def_expected, result);
+    printf ("FAIL: class def expected size %u but was %u\n", expected, result);
+    return false;
+  }
+
+  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: coverage expected size %u but was %u\n", expected, result);
     return false;
   }
 
@@ -57,43 +149,45 @@
 {
   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 @@
     {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/src/harfbuzz-cairo.pc.in b/src/harfbuzz-cairo.pc.in
index df97ff1..06ba804 100644
--- a/src/harfbuzz-cairo.pc.in
+++ b/src/harfbuzz-cairo.pc.in
@@ -8,5 +8,6 @@
 Version: %VERSION%
 
 Requires: harfbuzz = %VERSION%
+Requires.private: cairo
 Libs: -L${libdir} -lharfbuzz-cairo
 Cflags: -I${includedir}/harfbuzz
diff --git a/src/harfbuzz-subset.cc b/src/harfbuzz-subset.cc
index c0e23b3..f80c004 100644
--- a/src/harfbuzz-subset.cc
+++ b/src/harfbuzz-subset.cc
@@ -54,6 +54,7 @@
 #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"
diff --git a/src/hb-aat-layout-ankr-table.hh b/src/hb-aat-layout-ankr-table.hh
index 63fac84..dbb38b1 100644
--- a/src/hb-aat-layout-ankr-table.hh
+++ b/src/hb-aat-layout-ankr-table.hh
@@ -75,6 +75,7 @@
   {
     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/src/hb-aat-layout-bsln-table.hh b/src/hb-aat-layout-bsln-table.hh
index bf12d2e..8e42fab 100644
--- a/src/hb-aat-layout-bsln-table.hh
+++ b/src/hb-aat-layout-bsln-table.hh
@@ -123,6 +123,7 @@
     TRACE_SANITIZE (this);
     if (unlikely (!(c->check_struct (this) && defaultBaseline < 32)))
       return_trace (false);
+    hb_barrier ();
 
     switch (format)
     {
diff --git a/src/hb-aat-layout-common.hh b/src/hb-aat-layout-common.hh
index 672f80e..c26f376 100644
--- a/src/hb-aat-layout-common.hh
+++ b/src/hb-aat-layout-common.hh
@@ -46,8 +46,9 @@
        hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
 {
   const char *get_name () { return "APPLY"; }
-  template <typename T>
-  return_t dispatch (const T &obj) { return obj.apply (this); }
+  template <typename T, typename ...Ts>
+  return_t dispatch (const T &obj, Ts&&... ds)
+  { return obj.apply (this, std::forward<Ts> (ds)...); }
   static return_t default_return_value () { return false; }
   bool stop_sublookup_iteration (return_t r) const { return r; }
 
@@ -59,6 +60,9 @@
   const ankr *ankr_table;
   const OT::GDEF *gdef_table;
   const hb_sorted_vector_t<hb_aat_map_t::range_flags_t> *range_flags = nullptr;
+  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. */
@@ -81,6 +85,8 @@
  * Lookup Table
  */
 
+enum { DELETED_GLYPH = 0xFFFF };
+
 template <typename T> struct Lookup;
 
 template <typename T>
@@ -95,6 +101,12 @@
     return &arrayZ[glyph_id];
   }
 
+  template <typename set_t>
+  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);
@@ -123,6 +135,14 @@
   int cmp (hb_codepoint_t g) const
   { return g < first ? -1 : g <= last ? 0 : +1 ; }
 
+  template <typename set_t>
+  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);
@@ -153,6 +173,14 @@
     return v ? &v->value : nullptr;
   }
 
+  template <typename set_t>
+  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);
@@ -184,6 +212,14 @@
     return first <= glyph_id && glyph_id <= last ? &(base+valuesZ)[glyph_id - first] : nullptr;
   }
 
+  template <typename set_t>
+  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; }
 
@@ -191,6 +227,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
+		  hb_barrier () &&
 		  first <= last &&
 		  valuesZ.sanitize (c, base, last - first + 1));
   }
@@ -199,6 +236,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
+		  hb_barrier () &&
 		  first <= last &&
 		  valuesZ.sanitize (c, base, last - first + 1, std::forward<Ts> (ds)...));
   }
@@ -224,6 +262,14 @@
     return v ? v->get_value (glyph_id, this) : nullptr;
   }
 
+  template <typename set_t>
+  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);
@@ -252,6 +298,14 @@
 
   int cmp (hb_codepoint_t g) const { return glyph.cmp (g); }
 
+  template <typename set_t>
+  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);
@@ -281,6 +335,14 @@
     return v ? &v->value : nullptr;
   }
 
+  template <typename set_t>
+  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);
@@ -312,6 +374,16 @@
 	   &valueArrayZ[glyph_id - firstGlyph] : nullptr;
   }
 
+  template <typename set_t>
+  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);
@@ -356,10 +428,21 @@
     return v;
   }
 
+  template <typename set_t>
+  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));
   }
@@ -403,6 +486,20 @@
     }
   }
 
+  template <typename set_t>
+  void collect_glyphs (set_t &glyphs, unsigned int num_glyphs) const
+  {
+    switch (u.format) {
+    case 0: u.format0.collect_glyphs (glyphs, num_glyphs); return;
+    case 2: u.format2.collect_glyphs (glyphs); return;
+    case 4: u.format4.collect_glyphs (glyphs); return;
+    case 6: u.format6.collect_glyphs (glyphs); return;
+    case 8: u.format8.collect_glyphs (glyphs); return;
+    case 10: 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
@@ -415,6 +512,7 @@
   {
     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));
@@ -429,6 +527,7 @@
   {
     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));
@@ -455,8 +554,6 @@
 };
 DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1 (AAT, Lookup, 2);
 
-enum { DELETED_GLYPH = 0xFFFF };
-
 /*
  * (Extended) State Table
  */
@@ -507,6 +604,14 @@
   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 <typename Types, typename Extra>
 struct StateTable
 {
@@ -519,21 +624,24 @@
     STATE_START_OF_TEXT = 0,
     STATE_START_OF_LINE = 1,
   };
-  enum Class
+
+  template <typename set_t>
+  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 <typename set_t>
+  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<Extra> *get_entries () const
@@ -542,7 +650,7 @@
   const Entry<Extra> &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<Extra> *entries = (this+entryTable).arrayZ;
@@ -558,6 +666,7 @@
   {
     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);
 
@@ -684,6 +793,15 @@
   {
     return get_class (glyph_id, outOfRange);
   }
+
+  template <typename set_t>
+  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);
@@ -697,6 +815,38 @@
   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<NNOffset32To<UnsizedArrayOf<HBUINT8>>> 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<HBUINT8> coverageBitfields; *//* The individual coverage bitfields. */
+  public:
+  DEFINE_SIZE_ARRAY (0, subtableOffsets);
+};
+
 struct ObsoleteTypes
 {
   static constexpr bool extended = false;
@@ -773,15 +923,15 @@
   using EntryT = Entry<EntryData>;
 
   StateTableDriver (const StateTableT &machine_,
-		    hb_buffer_t *buffer_,
 		    hb_face_t *face_) :
 	      machine (machine_),
-	      buffer (buffer_),
 	      num_glyphs (face_->get_num_glyphs ()) {}
 
-  template <typename context_t>
+  template <typename context_t, typename set_t = hb_set_digest_t>
   void drive (context_t *c, hb_aat_apply_context_t *ac)
   {
+    hb_buffer_t *buffer = ac->buffer;
+
     if (!c->in_place)
       buffer->clear_output ();
 
@@ -816,9 +966,9 @@
 	}
       }
 
-      unsigned int klass = buffer->idx < buffer->len ?
-			   machine.get_class (buffer->cur().codepoint, num_glyphs) :
-			   (unsigned) StateTableT::CLASS_END_OF_TEXT;
+      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);
@@ -856,22 +1006,22 @@
       {
           /* 2c. */
           const auto wouldbe_entry = machine.get_entry(StateTableT::STATE_START_OF_TEXT, klass);
-      
+
           /* 2c'. */
-          if (c->is_actionable (this, wouldbe_entry))
-              return false;
-      
+          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 (this, entry))
+          if (c->is_actionable (buffer, this, entry))
               return false;
-      
+
           /* 2. */
           // This one is meh, I know...
           const auto ok =
@@ -880,15 +1030,15 @@
               || is_safe_to_break_extra();
           if (!ok)
               return false;
-      
+
           /* 3. */
-          return !c->is_actionable (this, machine.get_entry (state, StateTableT::CLASS_END_OF_TEXT));
+          return !c->is_actionable (buffer, this, machine.get_entry (state, CLASS_END_OF_TEXT));
       };
 
       if (!is_safe_to_break () && buffer->backtrack_len () && buffer->idx < buffer->len)
 	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);
@@ -906,7 +1056,6 @@
 
   public:
   const StateTableT &machine;
-  hb_buffer_t *buffer;
   unsigned int num_glyphs;
 };
 
diff --git a/src/hb-aat-layout-feat-table.hh b/src/hb-aat-layout-feat-table.hh
index 815a1fd..4fbec33 100644
--- a/src/hb-aat-layout-feat-table.hh
+++ b/src/hb-aat-layout-feat-table.hh
@@ -138,6 +138,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (likely (c->check_struct (this) &&
+			  hb_barrier () &&
 			  (base+settingTableZ).sanitize (c, nSettings)));
   }
 
@@ -200,6 +201,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (likely (c->check_struct (this) &&
+			  hb_barrier () &&
 			  version.major == 1 &&
 			  namesZ.sanitize (c, featureNameCount, this)));
   }
diff --git a/src/hb-aat-layout-just-table.hh b/src/hb-aat-layout-just-table.hh
index 8fd3990..ee08da1 100644
--- a/src/hb-aat-layout-just-table.hh
+++ b/src/hb-aat-layout-just-table.hh
@@ -185,6 +185,7 @@
     TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this)))
       return_trace (false);
+    hb_barrier ();
 
     switch (u.header.actionType)
     {
@@ -220,6 +221,7 @@
     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 @@
     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/src/hb-aat-layout-kerx-table.hh b/src/hb-aat-layout-kerx-table.hh
index 35d7c84..8d0d87a 100644
--- a/src/hb-aat-layout-kerx-table.hh
+++ b/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 @@
   unsigned int offset = value;
   const FWORD *pv = &StructAtOffset<FWORD> (base, offset);
   if (unlikely (!c->sanitizer.check_array (pv, tupleCount))) return 0;
+  hb_barrier ();
   return *pv;
 }
 
@@ -81,7 +83,7 @@
     return_trace (c->check_struct (this));
   }
 
-  protected:
+  public:
   HBGlyphID16	left;
   HBGlyphID16	right;
   FWORD		value;
@@ -117,6 +119,16 @@
     return_trace (true);
   }
 
+  template <typename set_t>
+  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 +139,10 @@
 		     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 +242,14 @@
 	depth (0),
 	crossStream (table->header.coverage & table->header.CrossStream) {}
 
-    bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
+    bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
+			StateTableDriver<Types, EntryData> *driver HB_UNUSED,
 			const Entry<EntryData> &entry)
     { return Format1EntryT::performAction (entry); }
-    void transition (StateTableDriver<Types, EntryData> *driver,
+    void transition (hb_buffer_t *buffer,
+		     StateTableDriver<Types, EntryData> *driver,
 		     const Entry<EntryData> &entry)
     {
-      hb_buffer_t *buffer = driver->buffer;
       unsigned int flags = entry.flags;
 
       if (flags & Format1EntryT::Reset)
@@ -259,6 +275,7 @@
 	  depth = 0;
 	  return;
 	}
+	hb_barrier ();
 
 	hb_mask_t kern_mask = c->plan->kern_mask;
 
@@ -349,7 +366,7 @@
 
     driver_context_t dc (this, c);
 
-    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->font->face);
+    StateTableDriver<Types, EntryData> driver (machine, c->font->face);
     driver.drive (&dc, c);
 
     return_trace (true);
@@ -363,12 +380,21 @@
 			  machine.sanitize (c)));
   }
 
+  template <typename set_t>
+  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<Types, EntryData>			machine;
   NNOffsetTo<UnsizedArrayOf<FWORD>, HBUINT>	kernAction;
   public:
-  DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 5 * sizeof (HBUINT));
+  DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + (StateTable<Types, EntryData>::static_size + HBUINT::static_size));
 };
 
 template <typename KernSubTableHeader>
@@ -389,6 +415,7 @@
     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);
   }
@@ -410,6 +437,13 @@
     return_trace (true);
   }
 
+  template <typename set_t>
+  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 +454,10 @@
 		     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 +466,7 @@
     return_trace (likely (c->check_struct (this) &&
 			  leftClassTable.sanitize (c, this) &&
 			  rightClassTable.sanitize (c, this) &&
+			  hb_barrier () &&
 			  c->check_range (this, array)));
   }
 
@@ -489,14 +527,14 @@
 	mark_set (false),
 	mark (0) {}
 
-    bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
+    bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
+			StateTableDriver<Types, EntryData> *driver HB_UNUSED,
 			const Entry<EntryData> &entry)
     { return entry.data.ankrActionIndex != 0xFFFF; }
-    void transition (StateTableDriver<Types, EntryData> *driver,
+    void transition (hb_buffer_t *buffer,
+		     StateTableDriver<Types, EntryData> *driver,
 		     const Entry<EntryData> &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 +547,7 @@
 	       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 +576,7 @@
 	       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 +597,7 @@
 	       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,7 +634,7 @@
 
     driver_context_t dc (this, c);
 
-    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->font->face);
+    StateTableDriver<Types, EntryData> driver (machine, c->font->face);
     driver.drive (&dc, c);
 
     return_trace (true);
@@ -607,12 +648,21 @@
 			  machine.sanitize (c)));
   }
 
+  template <typename set_t>
+  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<Types, EntryData>	machine;
   HBUINT32			flags;
   public:
-  DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 20);
+  DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + (StateTable<Types, EntryData>::static_size + HBUINT32::static_size));
 };
 
 template <typename KernSubTableHeader>
@@ -631,7 +681,7 @@
     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 +689,18 @@
       if (unlikely (hb_unsigned_mul_overflows (offset, sizeof (FWORD32)))) return 0;
       const FWORD32 *v = &StructAtOffset<FWORD32> (&(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<FWORD> (&(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);
     }
   }
@@ -674,6 +726,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (likely (c->check_struct (this) &&
+			  hb_barrier () &&
 			  (is_long () ?
 			   (
 			     u.l.rowIndexTable.sanitize (c, this) &&
@@ -688,6 +741,23 @@
 			   c->check_range (this, vector))));
   }
 
+  template <typename set_t>
+  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 +768,10 @@
 		     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 +857,27 @@
     }
   }
 
+  template <typename set_t>
+  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 +901,8 @@
  * The 'kerx' Table
  */
 
+using kern_accelerator_data_t = hb_vector_t<hb_pair_t<hb_set_digest_t, hb_set_digest_t>>;
+
 template <typename T>
 struct KerxTable
 {
@@ -867,7 +957,8 @@
     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 ();
 
@@ -914,6 +1005,16 @@
       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);
@@ -936,9 +1037,10 @@
   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;
@@ -949,6 +1051,7 @@
     {
       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
@@ -964,8 +1067,61 @@
       st = &StructAfter<SubTable> (*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<SubTable> (*st);
+    }
+
+    return accel_data;
+  }
+
+  struct accelerator_t
+  {
+    accelerator_t (hb_face_t *face)
+    {
+      hb_sanitize_context_t sc;
+      this->table = sc.reference_table<T> (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<T> table;
+    kern_accelerator_data_t accel_data;
+  };
 };
 
 struct kerx : KerxTable<kerx>
@@ -994,8 +1150,10 @@
   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/src/hb-aat-layout-morx-table.hh b/src/hb-aat-layout-morx-table.hh
index f41ecc1..4a94e6a 100644
--- a/src/hb-aat-layout-morx-table.hh
+++ b/src/hb-aat-layout-morx-table.hh
@@ -74,15 +74,16 @@
 	ret (false),
 	start (0), end (0) {}
 
-    bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
-			const Entry<EntryData> &entry)
+    bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
+			StateTableDriver<Types, EntryData> *driver HB_UNUSED,
+			const Entry<EntryData> &entry) const
     {
       return (entry.flags & Verb) && start < end;
     }
-    void transition (StateTableDriver<Types, EntryData> *driver,
+    void transition (hb_buffer_t *buffer,
+		     StateTableDriver<Types, EntryData> *driver,
 		     const Entry<EntryData> &entry)
     {
-      hb_buffer_t *buffer = driver->buffer;
       unsigned int flags = entry.flags;
 
       if (flags & MarkFirst)
@@ -168,7 +169,7 @@
 
     driver_context_t dc (this);
 
-    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
+    StateTableDriver<Types, EntryData> driver (machine, c->face);
     driver.drive (&dc, c);
 
     return_trace (dc.ret);
@@ -180,10 +181,10 @@
     return_trace (machine.sanitize (c));
   }
 
-  protected:
+  public:
   StateTable<Types, EntryData>	machine;
   public:
-  DEFINE_SIZE_STATIC (16);
+  DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size));
 };
 
 template <typename Types>
@@ -223,21 +224,19 @@
 	table (table_),
 	subs (table+table->substitutionTables) {}
 
-    bool is_actionable (StateTableDriver<Types, EntryData> *driver,
-			const Entry<EntryData> &entry)
+    bool is_actionable (hb_buffer_t *buffer,
+			StateTableDriver<Types, EntryData> *driver,
+			const Entry<EntryData> &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<Types, EntryData> *driver,
+    void transition (hb_buffer_t *buffer,
+		     StateTableDriver<Types, EntryData> *driver,
 		     const Entry<EntryData> &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,7 +258,9 @@
 	unsigned int offset = entry.data.markIndex + buffer->info[mark].codepoint;
 	const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) 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)
@@ -287,7 +288,9 @@
 	unsigned int offset = entry.data.currentIndex + buffer->info[idx].codepoint;
 	const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) 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)
@@ -315,7 +318,7 @@
     bool has_glyph_classes;
     unsigned int mark;
     const ContextualSubtable *table;
-    const UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, false> &subs;
+    const UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, void, false> &subs;
   };
 
   bool apply (hb_aat_apply_context_t *c) const
@@ -324,7 +327,7 @@
 
     driver_context_t dc (this, c);
 
-    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
+    StateTableDriver<Types, EntryData> driver (machine, c->face);
     driver.drive (&dc, c);
 
     return_trace (dc.ret);
@@ -336,6 +339,7 @@
 
     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 +360,14 @@
     return_trace (substitutionTables.sanitize (c, this, num_lookups));
   }
 
-  protected:
+  public:
   StateTable<Types, EntryData>
 		machine;
-  NNOffsetTo<UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, false>, HBUINT>
+  protected:
+  NNOffsetTo<UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, void, false>, HBUINT>
 		substitutionTables;
   public:
-  DEFINE_SIZE_STATIC (20);
+  DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size + HBUINT::static_size));
 };
 
 
@@ -459,16 +464,16 @@
 	ligature (table+table->ligature),
 	match_length (0) {}
 
-    bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
-			const Entry<EntryData> &entry)
+    bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
+			StateTableDriver<Types, EntryData> *driver HB_UNUSED,
+			const Entry<EntryData> &entry) const
     {
       return LigatureEntryT::performAction (entry);
     }
-    void transition (StateTableDriver<Types, EntryData> *driver,
+    void transition (hb_buffer_t *buffer,
+		     StateTableDriver<Types, EntryData> *driver,
 		     const Entry<EntryData> &entry)
     {
-      hb_buffer_t *buffer = driver->buffer;
-
       DEBUG_MSG (APPLY, nullptr, "Ligature transition at %u", buffer->idx);
       if (entry.flags & LigatureEntryT::SetComponent)
       {
@@ -513,6 +518,7 @@
 	  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,6 +529,7 @@
 	  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 %d last %d",
@@ -533,6 +540,7 @@
 	    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 +552,7 @@
 	    {
 	      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,7 +585,7 @@
 
     driver_context_t dc (this, c);
 
-    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
+    StateTableDriver<Types, EntryData> driver (machine, c->face);
     driver.drive (&dc, c);
 
     return_trace (dc.ret);
@@ -587,12 +596,14 @@
     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<Types, EntryData>
 		machine;
+  protected:
   NNOffsetTo<UnsizedArrayOf<HBUINT32>, HBUINT>
 		ligAction;	/* Offset to the ligature action table. */
   NNOffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT>
@@ -600,7 +611,7 @@
   NNOffsetTo<UnsizedArrayOf<HBGlyphID16>, HBUINT>
 		ligature;	/* Offset to the actual ligature lists. */
   public:
-  DEFINE_SIZE_STATIC (28);
+  DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size + 3 * HBUINT::static_size));
 };
 
 template <typename Types>
@@ -744,16 +755,17 @@
 	mark (0),
 	insertionAction (table+table->insertionAction) {}
 
-    bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
-			const Entry<EntryData> &entry)
+    bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
+			StateTableDriver<Types, EntryData> *driver HB_UNUSED,
+			const Entry<EntryData> &entry) const
     {
       return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) &&
 	     (entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF);
     }
-    void transition (StateTableDriver<Types, EntryData> *driver,
+    void transition (hb_buffer_t *buffer,
+		     StateTableDriver<Types, EntryData> *driver,
 		     const Entry<EntryData> &entry)
     {
-      hb_buffer_t *buffer = driver->buffer;
       unsigned int flags = entry.flags;
 
       unsigned mark_loc = buffer->out_len;
@@ -765,6 +777,7 @@
 	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;
 
@@ -793,6 +806,7 @@
 	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;
 
@@ -838,7 +852,7 @@
 
     driver_context_t dc (this, c);
 
-    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
+    StateTableDriver<Types, EntryData> driver (machine, c->face);
     driver.drive (&dc, c);
 
     return_trace (dc.ret);
@@ -849,17 +863,19 @@
     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<Types, EntryData>
 		machine;
+  protected:
   NNOffsetTo<UnsizedArrayOf<HBGlyphID16>, HBUINT>
 		insertionAction;	/* Byte offset from stateHeader to the start of
 					 * the insertion glyph table. */
   public:
-  DEFINE_SIZE_STATIC (20);
+  DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size + HBUINT::static_size));
 };
 
 
@@ -883,6 +899,89 @@
   DEFINE_SIZE_STATIC (12);
 };
 
+
+struct hb_accelerate_subtables_context_t :
+       hb_dispatch_context_t<hb_accelerate_subtables_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 <typename T>
+    auto init_ (const T &obj_, unsigned num_glyphs, hb_priority<1>) HB_AUTO_RETURN
+    (
+      obj_.machine.collect_glyphs (this->digest, num_glyphs)
+    )
+
+    template <typename T>
+    void init_ (const T &obj_, unsigned num_glyphs, hb_priority<0>)
+    {
+      digest = digest.full ();
+    }
+
+    template <typename T>
+    void init (const T &obj_, unsigned num_glyphs)
+    {
+      init_ (obj_, num_glyphs, hb_prioritize);
+    }
+  };
+
+  /* Dispatch interface. */
+  template <typename T>
+  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<hb_accelerate_subtables_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 <typename TChain>
+  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 <typename Types>
 struct ChainSubtable
 {
@@ -944,9 +1043,10 @@
   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);
@@ -973,6 +1073,8 @@
 {
   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;
@@ -1013,7 +1115,8 @@
     return flags;
   }
 
-  void apply (hb_aat_apply_context_t *c) const
+  void apply (hb_aat_apply_context_t *c,
+	      const hb_aat_layout_chain_accelerator_t *accel) const
   {
     const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
     unsigned int count = subtableCount;
@@ -1025,6 +1128,7 @@
 		   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<Types>::AllDirections) &&
 	  HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
@@ -1086,12 +1190,28 @@
 
   unsigned int get_size () const { return length; }
 
-  bool sanitize (hb_sanitize_context_t *c, unsigned int version HB_UNUSED) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (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<Ts> (ds)...);
+      if (c->stop_sublookup_iteration (ret))
+	return ret;
+      subtable = &StructAfter<ChainSubtable<Types>> (*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))
@@ -1103,9 +1223,17 @@
     {
       if (!subtable->sanitize (c))
 	return_trace (false);
+      hb_barrier ();
       subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
     }
 
+    if (version >= 3)
+    {
+      const SubtableGlyphCoverage *coverage = (const SubtableGlyphCoverage *) subtable;
+      if (!coverage->sanitize (c, count))
+        return_trace (false);
+    }
+
     return_trace (true);
   }
 
@@ -1117,7 +1245,7 @@
 
   UnsizedArrayOf<Feature>	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));
@@ -1128,13 +1256,69 @@
  * The 'mort'/'morx' Table
  */
 
-template <typename Types, hb_tag_t TAG>
+template <typename T, typename Types, hb_tag_t TAG>
 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<T> (face);
+
+      this->chain_count = table->get_chain_count ();
+
+      this->accels = (hb_atomic_ptr_t<hb_aat_layout_chain_accelerator_t> *) hb_calloc (this->chain_count, sizeof (*accels));
+      if (unlikely (!this->accels))
+      {
+	this->chain_count = 0;
+	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 <typename Chain>
+    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<T> table;
+    unsigned int chain_count;
+    hb_atomic_ptr_t<hb_aat_layout_chain_accelerator_t> *accels;
+  };
+
+
   void compile_flags (const hb_aat_map_builder_t *mapper,
 		      hb_aat_map_t *map) const
   {
@@ -1151,8 +1335,14 @@
     }
   }
 
+  unsigned get_chain_count () const
+  {
+	  return chainCount;
+  }
+
   void apply (hb_aat_apply_context_t *c,
-	      const hb_aat_map_t &map) const
+	      const hb_aat_map_t &map,
+	      const accelerator_t &accel) const
   {
     if (unlikely (!c->buffer->successful)) return;
 
@@ -1163,8 +1353,9 @@
     unsigned int count = chainCount;
     for (unsigned int i = 0; i < count; 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->apply (c, chain_accel);
       if (unlikely (!c->buffer->successful)) return;
       chain = &StructAfter<Chain<Types>> (*chain);
     }
@@ -1173,7 +1364,10 @@
   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<Types> *chain = &firstChain;
@@ -1182,6 +1376,7 @@
     {
       if (!chain->sanitize (c, version))
 	return_trace (false);
+      hb_barrier ();
       chain = &StructAfter<Chain<Types>> (*chain);
     }
 
@@ -1200,8 +1395,15 @@
   DEFINE_SIZE_MIN (8);
 };
 
-struct morx : mortmorx<ExtendedTypes, HB_AAT_TAG_morx> {};
-struct mort : mortmorx<ObsoleteTypes, HB_AAT_TAG_mort> {};
+struct morx : mortmorx<morx, ExtendedTypes, HB_AAT_TAG_morx> {};
+struct mort : mortmorx<mort, ObsoleteTypes, HB_AAT_TAG_mort> {};
+
+struct morx_accelerator_t : morx::accelerator_t {
+  morx_accelerator_t (hb_face_t *face) : morx::accelerator_t (face) {}
+};
+struct mort_accelerator_t : mort::accelerator_t {
+  mort_accelerator_t (hb_face_t *face) : mort::accelerator_t (face) {}
+};
 
 
 } /* namespace AAT */
diff --git a/src/hb-aat-layout-opbd-table.hh b/src/hb-aat-layout-opbd-table.hh
index 51b650f..9840d3a 100644
--- a/src/hb-aat-layout-opbd-table.hh
+++ b/src/hb-aat-layout-opbd-table.hh
@@ -144,6 +144,7 @@
     TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this) || version.major != 1))
       return_trace (false);
+    hb_barrier ();
 
     switch (format)
     {
diff --git a/src/hb-aat-layout-trak-table.hh b/src/hb-aat-layout-trak-table.hh
index c72c086..345a236 100644
--- a/src/hb-aat-layout-trak-table.hh
+++ b/src/hb-aat-layout-trak-table.hh
@@ -134,6 +134,7 @@
   {
     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 @@
     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/src/hb-aat-layout.cc b/src/hb-aat-layout.cc
index 5e4cea2..9da29e5 100644
--- a/src/hb-aat-layout.cc
+++ b/src/hb-aat-layout.cc
@@ -211,14 +211,14 @@
 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);
@@ -243,8 +243,8 @@
 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
@@ -260,26 +260,30 @@
   hb_aat_map_t map;
   builder.compile (map);
 
-  hb_blob_t *morx_blob = font->face->table.morx.get_blob ();
-  const AAT::morx& morx = *morx_blob->as<AAT::morx> ();
-  if (morx.has_data ())
   {
-    AAT::hb_aat_apply_context_t c (plan, font, buffer, morx_blob);
-    if (!buffer->message (font, "start table morx")) return;
-    morx.apply (&c, map);
-    (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<AAT::mort> ();
-  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, map);
-    (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;
+    }
   }
 }
 
@@ -322,7 +326,7 @@
 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
@@ -330,13 +334,12 @@
 			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<AAT::kerx> ();
+  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/src/hb-aat-layout.h b/src/hb-aat-layout.h
index 9af2740..c682a2f 100644
--- a/src/hb-aat-layout.h
+++ b/src/hb-aat-layout.h
@@ -40,7 +40,7 @@
  * @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 @@
 
   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/src/hb-aat-ltag-table.hh b/src/hb-aat-ltag-table.hh
index 6d771e1..c974025 100644
--- a/src/hb-aat-ltag-table.hh
+++ b/src/hb-aat-ltag-table.hh
@@ -46,7 +46,9 @@
   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 @@
   {
     TRACE_SANITIZE (this);
     return_trace (likely (c->check_struct (this) &&
+			  hb_barrier () &&
 			  version >= 1 &&
 			  tagRanges.sanitize (c, this)));
   }
diff --git a/src/hb-algs.hh b/src/hb-algs.hh
index ea97057..b02793a 100644
--- a/src/hb-algs.hh
+++ b/src/hb-algs.hh
@@ -202,8 +202,12 @@
 /* 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)
 
 
@@ -671,7 +675,7 @@
     return 0;
   }
 
-  friend void swap (hb_pair_t& a, hb_pair_t& b)
+  friend void swap (hb_pair_t& a, hb_pair_t& b) noexcept
   {
     hb_swap (a.first, b.first);
     hb_swap (a.second, b.second);
@@ -1053,6 +1057,18 @@
   return val.cmp (key, ds...);
 }
 
+template <typename K, typename V>
+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 <typename V, typename K, typename ...Ts>
 static inline bool
 hb_bsearch_impl (unsigned *pos, /* Out */
diff --git a/src/hb-array.hh b/src/hb-array.hh
index 760f902..9037179 100644
--- a/src/hb-array.hh
+++ b/src/hb-array.hh
@@ -47,6 +47,8 @@
 template <typename Type>
 struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
 {
+  static constexpr bool realloc_move = true;
+
   /*
    * Constructors.
    */
diff --git a/src/hb-atomic.hh b/src/hb-atomic.hh
index 303dfe6..366fb32 100644
--- a/src/hb-atomic.hh
+++ b/src/hb-atomic.hh
@@ -118,12 +118,12 @@
  */
 #ifndef _hb_compiler_memory_r_barrier
 #if defined(__ATOMIC_ACQUIRE) // gcc-like
-#define _hb_compiler_memory_r_barrier() asm volatile("": : :"memory")
+static inline void _hb_compiler_memory_r_barrier () { asm volatile("": : :"memory"); }
 #elif !defined(_MSC_VER)
 #include <atomic>
 #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
 
@@ -218,5 +218,11 @@
   T *v = nullptr;
 };
 
+static inline bool hb_barrier ()
+{
+  _hb_compiler_memory_r_barrier ();
+  return true;
+}
+
 
 #endif /* HB_ATOMIC_HH */
diff --git a/src/hb-bit-set-invertible.hh b/src/hb-bit-set-invertible.hh
index e765a47..d5d1326 100644
--- a/src/hb-bit-set-invertible.hh
+++ b/src/hb-bit-set-invertible.hh
@@ -39,10 +39,10 @@
 
   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;
@@ -359,8 +359,8 @@
     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
diff --git a/src/hb-bit-set.hh b/src/hb-bit-set.hh
index 1dbcce5..5f4c6f0 100644
--- a/src/hb-bit-set.hh
+++ b/src/hb-bit-set.hh
@@ -38,10 +38,10 @@
   ~hb_bit_set_t () = default;
 
   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) : hb_bit_set_t () { hb_swap (*this, other); }
+  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;
diff --git a/src/hb-blob.cc b/src/hb-blob.cc
index 265effb..873d9b2 100644
--- a/src/hb-blob.cc
+++ b/src/hb-blob.cc
@@ -598,6 +598,11 @@
  * 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.
  *
@@ -617,6 +622,11 @@
  * 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 `NULL` if failed.
  *
@@ -672,10 +682,19 @@
   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);
+
+  /* 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 };
diff --git a/src/hb-buffer-verify.cc b/src/hb-buffer-verify.cc
index 15a5391..671d6ed 100644
--- a/src/hb-buffer-verify.cc
+++ b/src/hb-buffer-verify.cc
@@ -149,7 +149,7 @@
     }
     assert (text_start < text_end);
 
-    if (0)
+    if (false)
       printf("start %u end %u text start %u end %u\n", start, end, text_start, text_end);
 
     hb_buffer_clear_contents (fragment);
@@ -288,7 +288,7 @@
       }
       assert (text_start < text_end);
 
-      if (0)
+      if (false)
 	printf("start %u end %u text start %u end %u\n", start, end, text_start, text_end);
 
 #if 0
diff --git a/src/hb-buffer.cc b/src/hb-buffer.cc
index 934c6c2..d621a7c 100644
--- a/src/hb-buffer.cc
+++ b/src/hb-buffer.cc
@@ -309,6 +309,7 @@
 
   deallocate_var_all ();
   serial = 0;
+  random_state = 1;
   scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
 }
 
@@ -1359,6 +1360,49 @@
   return buffer->not_found;
 }
 
+/**
+ * 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:
diff --git a/src/hb-buffer.h b/src/hb-buffer.h
index 3573127..f75fe96 100644
--- a/src/hb-buffer.h
+++ b/src/hb-buffer.h
@@ -487,6 +487,12 @@
 HB_EXTERN hb_codepoint_t
 hb_buffer_get_not_found_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.
diff --git a/src/hb-buffer.hh b/src/hb-buffer.hh
index f04ad58..0a19872 100644
--- a/src/hb-buffer.hh
+++ b/src/hb-buffer.hh
@@ -116,6 +116,7 @@
 
   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. */
diff --git a/src/hb-cff-interp-dict-common.hh b/src/hb-cff-interp-dict-common.hh
index 53226b2..a08b10b 100644
--- a/src/hb-cff-interp-dict-common.hh
+++ b/src/hb-cff-interp-dict-common.hh
@@ -54,8 +54,8 @@
   }
   void fini () { dict_values_t<OPSTR>::fini (); }
 
-  unsigned int  charStringsOffset;
-  unsigned int  FDArrayOffset;
+  int  charStringsOffset;
+  int  FDArrayOffset;
 };
 
 struct dict_opset_t : opset_t<number_t>
@@ -157,11 +157,11 @@
   {
     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/src/hb-cff2-interp-cs.hh b/src/hb-cff2-interp-cs.hh
index 915b10c..06fbb72 100644
--- a/src/hb-cff2-interp-cs.hh
+++ b/src/hb-cff2-interp-cs.hh
@@ -76,16 +76,12 @@
     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 ();
   }
 
@@ -168,13 +164,13 @@
   protected:
   const int     *coords;
   unsigned int  num_coords;
-  const	 CFF2VariationStore *varStore;
+  const	 CFF2ItemVariationStore *varStore;
   unsigned int  region_count;
   unsigned int  ivs;
   hb_vector_t<float>  scalars;
   bool	  do_blend;
-  bool	  seen_vsindex_;
-  bool	  seen_blend;
+  bool	  seen_vsindex_ = false;
+  bool	  seen_blend = false;
 
   typedef cs_interp_env_t<ELEM, CFF2Subrs> SUPER;
 };
diff --git a/src/hb-common.cc b/src/hb-common.cc
index 6277f46..f3d6d12 100644
--- a/src/hb-common.cc
+++ b/src/hb-common.cc
@@ -997,7 +997,7 @@
   if (feature->value > 1)
   {
     s[len++] = '=';
-    len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%" PRIu32 "", 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);
diff --git a/src/hb-common.h b/src/hb-common.h
index a9fe666..533de91 100644
--- a/src/hb-common.h
+++ b/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 <inttypes.h>
-#elif defined (_AIX)
+#if defined (_AIX)
 #  include <sys/inttypes.h>
 #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 unsigned __int32 uint32_t;
 typedef __int64 int64_t;
 typedef unsigned __int64 uint64_t;
-#elif defined (__KERNEL__)
-#  include <linux/types.h>
-#else
+#elif defined (_MSC_VER) && _MSC_VER < 1800
+/* VS 2013 (_MSC_VER 1800) has inttypes.h */
 #  include <stdint.h>
+#else
+#  include <inttypes.h>
 #endif
 
 #if defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
diff --git a/src/hb-cplusplus.hh b/src/hb-cplusplus.hh
index 531ef1b..b6b5c8f 100644
--- a/src/hb-cplusplus.hh
+++ b/src/hb-cplusplus.hh
@@ -27,9 +27,6 @@
 
 #include "hb.h"
 
-HB_BEGIN_DECLS
-HB_END_DECLS
-
 #ifdef __cplusplus
 
 #include <functional>
@@ -56,15 +53,15 @@
 
   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 @@
 
   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 (); }
diff --git a/src/hb-deprecated.h b/src/hb-deprecated.h
index 9fcce6d..ad19f9a 100644
--- a/src/hb-deprecated.h
+++ b/src/hb-deprecated.h
@@ -56,7 +56,7 @@
 /**
  * HB_SCRIPT_CANADIAN_ABORIGINAL:
  *
- * Use #HB_SCRIPT_CANADIAN_SYLLABICS instead:
+ * Use #HB_SCRIPT_CANADIAN_SYLLABICS instead.
  *
  * Deprecated: 0.9.20
  */
@@ -301,6 +301,15 @@
 			 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
 
 
diff --git a/src/hb-directwrite.cc b/src/hb-directwrite.cc
index 42764a2..6c90265 100644
--- a/src/hb-directwrite.cc
+++ b/src/hb-directwrite.cc
@@ -173,7 +173,7 @@
 
   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 @@
   p_DWriteCreateFactory = (t_DWriteCreateFactory)
 			  GetProcAddress (data->dwrite_dll, "DWriteCreateFactory");
 
-#if defined(__GNUC__)
+#if defined(__GNUC__) || defined(__clang__)
 #pragma GCC diagnostic pop
 #endif
 
diff --git a/src/hb-font.hh b/src/hb-font.hh
index a748ce5..b18f021 100644
--- a/src/hb-font.hh
+++ b/src/hb-font.hh
@@ -652,7 +652,7 @@
   {
     if (get_glyph_name (glyph, s, size)) return;
 
-    if (size && snprintf (s, size, "gid%" PRIu32 "", glyph) < 0)
+    if (size && snprintf (s, size, "gid%" PRIu32, glyph) < 0)
       *s = '\0';
   }
 
diff --git a/src/hb-ft.cc b/src/hb-ft.cc
index 6ca3f85..3de4a6d 100644
--- a/src/hb-ft.cc
+++ b/src/hb-ft.cc
@@ -224,8 +224,8 @@
  *
  * 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
+ * <https://freetype.org/freetype2/docs/reference/ft2-glyph_retrieval.html#ft_load_xxx>
  *
  * This function works with #hb_font_t objects created by
  * hb_ft_font_create() or hb_ft_font_create_referenced().
@@ -252,8 +252,8 @@
  *
  * 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
+ * <https://freetype.org/freetype2/docs/reference/ft2-glyph_retrieval.html#ft_load_xxx>
  *
  * This function works with #hb_font_t objects created by
  * hb_ft_font_create() or hb_ft_font_create_referenced().
@@ -1118,10 +1118,10 @@
  * 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
@@ -1215,7 +1215,7 @@
 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);
@@ -1241,13 +1241,13 @@
  * 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
diff --git a/src/hb-icu.cc b/src/hb-icu.cc
index e46401f..3707ec3 100644
--- a/src/hb-icu.cc
+++ b/src/hb-icu.cc
@@ -93,15 +93,16 @@
 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;
 }
 
 
diff --git a/src/hb-limits.hh b/src/hb-limits.hh
index 25c1e71..7efc893 100644
--- a/src/hb-limits.hh
+++ b/src/hb-limits.hh
@@ -106,7 +106,7 @@
 #endif
 
 #ifndef HB_COLRV1_MAX_EDGE_COUNT
-#define HB_COLRV1_MAX_EDGE_COUNT 65536
+#define HB_COLRV1_MAX_EDGE_COUNT 2048
 #endif
 
 
diff --git a/src/hb-map.hh b/src/hb-map.hh
index 13d6205..6521b1a 100644
--- a/src/hb-map.hh
+++ b/src/hb-map.hh
@@ -42,13 +42,37 @@
 	  bool minus_one = false>
 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 () { alloc (o.population); hb_copy (o, *this); }
-  hb_hashmap_t (hb_hashmap_t&& o) : hb_hashmap_t () { hb_swap (*this, o); }
+  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)  { hb_swap (*this, o); return *this; }
+  hb_hashmap_t& operator= (hb_hashmap_t&& o)   noexcept { hb_swap (*this, o); return *this; }
 
   hb_hashmap_t (std::initializer_list<hb_pair_t<K, V>> lst) : hb_hashmap_t ()
   {
@@ -113,26 +137,23 @@
   };
 
   hb_object_header_t header;
-  unsigned int successful : 1; /* Allocations successful */
-  unsigned int population : 31; /* Not including tombstones. */
+  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;
-  unsigned int max_chain_length;
   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;
-    unsigned tmp = a.population;
-    a.population = b.population;
-    b.population = tmp;
-    //hb_swap (a.population, b.population);
+    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);
     hb_swap (a.prime, b.prime);
-    hb_swap (a.max_chain_length, b.max_chain_length);
     hb_swap (a.items, b.items);
   }
   void init ()
@@ -140,10 +161,10 @@
     hb_object_init (this);
 
     successful = true;
+    max_chain_length = 0;
     population = occupancy = 0;
     mask = 0;
     prime = 0;
-    max_chain_length = 0;
     items = nullptr;
   }
   void fini ()
@@ -209,9 +230,10 @@
 		       old_items[i].hash,
 		       std::move (old_items[i].value));
       }
-      if (!item_t::is_trivial)
-	old_items[i].~item_t ();
     }
+    if (!item_t::is_trivial)
+      for (unsigned int i = 0; i < old_size; i++)
+	old_items[i].~item_t ();
 
     hb_free (old_items);
 
@@ -533,7 +555,7 @@
   ~hb_map_t () = default;
   hb_map_t () : hashmap () {}
   hb_map_t (const hb_map_t &o) : hashmap ((hashmap &) o) {}
-  hb_map_t (hb_map_t &&o) : hashmap (std::move ((hashmap &) o)) {}
+  hb_map_t (hb_map_t &&o)  noexcept : hashmap (std::move ((hashmap &) o)) {}
   hb_map_t& operator= (const hb_map_t&) = default;
   hb_map_t& operator= (hb_map_t&&) = default;
   hb_map_t (std::initializer_list<hb_codepoint_pair_t> lst) : hashmap (lst) {}
diff --git a/src/hb-object.hh b/src/hb-object.hh
index e2c2c33..5cffe16 100644
--- a/src/hb-object.hh
+++ b/src/hb-object.hh
@@ -325,7 +325,7 @@
   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/src/hb-open-file.hh b/src/hb-open-file.hh
index 04f144a..1157ea4 100644
--- a/src/hb-open-file.hh
+++ b/src/hb-open-file.hh
@@ -267,6 +267,7 @@
   {
     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));
@@ -302,6 +303,7 @@
     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 @@
   {
     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 @@
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
+		  hb_barrier () &&
 		  typeList.sanitize (c, this,
 				     &(this+typeList),
 				     data_base));
@@ -428,6 +432,7 @@
   {
     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 @@
   {
     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/src/hb-open-type.hh b/src/hb-open-type.hh
index d3fdd1c..9c11f14 100644
--- a/src/hb-open-type.hh
+++ b/src/hb-open-type.hh
@@ -309,7 +309,7 @@
   static       Type *get_crap () { return &Crap (Type); }
 };
 
-template <typename Type, typename OffsetType, bool has_null=true>
+template <typename Type, typename OffsetType, typename BaseType=void, bool has_null=true>
 struct OffsetTo : Offset<OffsetType, has_null>
 {
   using target_t = Type;
@@ -335,22 +335,22 @@
   }
 
   template <typename Base,
-	    hb_enable_if (hb_is_convertible (const Base, const void *))>
+	    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 <typename Base,
-	    hb_enable_if (hb_is_convertible (const Base, const void *))>
+	    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 <typename Base,
-	    hb_enable_if (hb_is_convertible (Base, void *))>
+	    hb_enable_if (hb_is_convertible (Base, BaseType *))>
   friend Type& operator + (Base &&base, OffsetTo &offset) { return offset ((void *) base); }
   template <typename Base,
-	    hb_enable_if (hb_is_convertible (Base, void *))>
+	    hb_enable_if (hb_is_convertible (Base, BaseType *))>
   friend Type& operator + (OffsetTo &offset, Base &&base) { return offset ((void *) base); }
 
 
-  template <typename ...Ts>
+  template <typename Base, typename ...Ts>
   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 ())
@@ -414,10 +414,11 @@
 		       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);
+    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);
@@ -427,10 +428,11 @@
 #ifndef HB_OPTIMIZE_SIZE
   HB_ALWAYS_INLINE
 #endif
-  bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const
+  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<Type> (base, *this), std::forward<Ts> (ds)...) ||
 		   neuter (c)));
@@ -445,14 +447,14 @@
   DEFINE_SIZE_STATIC (sizeof (OffsetType));
 };
 /* Partial specializations. */
-template <typename Type, bool has_null=true> using Offset16To = OffsetTo<Type, HBUINT16, has_null>;
-template <typename Type, bool has_null=true> using Offset24To = OffsetTo<Type, HBUINT24, has_null>;
-template <typename Type, bool has_null=true> using Offset32To = OffsetTo<Type, HBUINT32, has_null>;
+template <typename Type, typename BaseType=void, bool has_null=true> using Offset16To = OffsetTo<Type, HBUINT16, BaseType, has_null>;
+template <typename Type, typename BaseType=void, bool has_null=true> using Offset24To = OffsetTo<Type, HBUINT24, BaseType, has_null>;
+template <typename Type, typename BaseType=void, bool has_null=true> using Offset32To = OffsetTo<Type, HBUINT32, BaseType, has_null>;
 
-template <typename Type, typename OffsetType> using NNOffsetTo = OffsetTo<Type, OffsetType, false>;
-template <typename Type> using NNOffset16To = Offset16To<Type, false>;
-template <typename Type> using NNOffset24To = Offset24To<Type, false>;
-template <typename Type> using NNOffset32To = Offset32To<Type, false>;
+template <typename Type, typename OffsetType, typename BaseType=void> using NNOffsetTo = OffsetTo<Type, OffsetType, BaseType, false>;
+template <typename Type, typename BaseType=void> using NNOffset16To = Offset16To<Type, BaseType, false>;
+template <typename Type, typename BaseType=void> using NNOffset24To = Offset24To<Type, BaseType, false>;
+template <typename Type, typename BaseType=void> using NNOffset32To = Offset32To<Type, BaseType, false>;
 
 
 /*
@@ -536,6 +538,7 @@
     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<Ts> (ds)...)))
 	return_trace (false);
@@ -555,17 +558,17 @@
 };
 
 /* Unsized array of offset's */
-template <typename Type, typename OffsetType, bool has_null=true>
-using UnsizedArray16OfOffsetTo = UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null>>;
+template <typename Type, typename OffsetType, typename BaseType=void, bool has_null=true>
+using UnsizedArray16OfOffsetTo = UnsizedArrayOf<OffsetTo<Type, OffsetType, BaseType, has_null>>;
 
 /* Unsized array of offsets relative to the beginning of the array itself. */
-template <typename Type, typename OffsetType, bool has_null=true>
-struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo<Type, OffsetType, has_null>
+template <typename Type, typename OffsetType, typename BaseType=void, bool has_null=true>
+struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo<Type, OffsetType, BaseType, has_null>
 {
   const Type& operator [] (int i_) const
   {
     unsigned int i = (unsigned int) i_;
-    const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i];
+    const OffsetTo<Type, OffsetType, BaseType, has_null> *p = &this->arrayZ[i];
     if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Null (Type); /* Overflowed. */
     _hb_compiler_memory_r_barrier ();
     return this+*p;
@@ -573,7 +576,7 @@
   Type& operator [] (int i_)
   {
     unsigned int i = (unsigned int) i_;
-    const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i];
+    const OffsetTo<Type, OffsetType, BaseType, has_null> *p = &this->arrayZ[i];
     if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Crap (Type); /* Overflowed. */
     _hb_compiler_memory_r_barrier ();
     return this+*p;
@@ -583,7 +586,7 @@
   bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
-    return_trace ((UnsizedArray16OfOffsetTo<Type, OffsetType, has_null>
+    return_trace ((UnsizedArray16OfOffsetTo<Type, OffsetType, BaseType, has_null>
 		   ::sanitize (c, count, this, std::forward<Ts> (ds)...)));
   }
 };
@@ -725,6 +728,7 @@
     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<Ts> (ds)...)))
@@ -735,7 +739,9 @@
   bool sanitize_shallow (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (len.sanitize (c) && c->check_array_sized (arrayZ, len, sizeof (LenType)));
+    return_trace (len.sanitize (c) &&
+		  hb_barrier () &&
+		  c->check_array_sized (arrayZ, len, sizeof (LenType)));
   }
 
   public:
@@ -866,6 +872,7 @@
     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<Ts> (ds)...)))
@@ -878,6 +885,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (lenP1.sanitize (c) &&
+		  hb_barrier () &&
 		  (!lenP1 || c->check_array_sized (arrayZ, lenP1 - 1, sizeof (LenType))));
   }
 
@@ -919,6 +927,7 @@
     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<Ts> (ds)...)))
@@ -931,6 +940,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (lenM1.sanitize (c) &&
+		  hb_barrier () &&
 		  (c->check_array_sized (arrayZ, lenM1 + 1, sizeof (LenType))));
   }
 
@@ -975,6 +985,13 @@
     return_trace (ret);
   }
 
+  SortedArrayOf* copy (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    SortedArrayOf* out = reinterpret_cast<SortedArrayOf *> (ArrayOf<Type, LenType>::copy (c));
+    return_trace (out);
+  }
+
   template <typename T>
   Type &bsearch (const T &x, Type &not_found = Crap (Type))
   { return *as_array ().bsearch (x, &not_found); }
@@ -1104,6 +1121,7 @@
     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<Ts> (ds)...)))
@@ -1130,6 +1148,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (header.sanitize (c) &&
+		  hb_barrier () &&
 		  Type::static_size <= header.unitSize &&
 		  c->check_range (bytesZ.arrayZ,
 				  header.nUnits,
diff --git a/src/hb-ot-cff-common.hh b/src/hb-ot-cff-common.hh
index 923a32b..c7c3264 100644
--- a/src/hb-ot-cff-common.hh
+++ b/src/hb-ot-cff-common.hh
@@ -41,10 +41,21 @@
 using objidx_t = hb_serialize_context_t::objidx_t;
 using whence_t = hb_serialize_context_t::whence_t;
 
-/* utility macro */
-template<typename Type>
-static inline const Type& StructAtOffsetOrNull (const void *P, unsigned int offset)
-{ return offset ? StructAtOffset<Type> (P, offset) : Null (Type); }
+/* CFF offsets can technically be negative */
+template<typename Type, typename ...Ts>
+static inline const Type& StructAtOffsetOrNull (const void *P, int offset, hb_sanitize_context_t &sc, Ts&&... ds)
+{
+  if (!offset) return Null (Type);
+
+  const char *p = (const char *) P + offset;
+  if (!sc.check_point (p)) return Null (Type);
+
+  const Type &obj = *reinterpret_cast<const Type *> (p);
+  if (!obj.sanitize (&sc, std::forward<Ts> (ds)...)) return Null (Type);
+
+  return obj;
+}
+
 
 struct code_pair_t
 {
@@ -78,7 +89,8 @@
 	    hb_requires (hb_is_iterable (Iterable))>
   bool serialize (hb_serialize_context_t *c,
 		  const Iterable &iterable,
-		  const unsigned *p_data_size = nullptr)
+		  const unsigned *p_data_size = nullptr,
+                  unsigned min_off_size = 0)
   {
     TRACE_SERIALIZE (this);
     unsigned data_size;
@@ -88,7 +100,7 @@
       total_size (iterable, &data_size);
 
     auto it = hb_iter (iterable);
-    if (unlikely (!serialize_header (c, +it, data_size))) return_trace (false);
+    if (unlikely (!serialize_header (c, +it, data_size, min_off_size))) return_trace (false);
     unsigned char *ret = c->allocate_size<unsigned char> (data_size, false);
     if (unlikely (!ret)) return_trace (false);
     for (const auto &_ : +it)
@@ -111,11 +123,13 @@
 	    hb_requires (hb_is_iterator (Iterator))>
   bool serialize_header (hb_serialize_context_t *c,
 			 Iterator it,
-			 unsigned data_size)
+			 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);
@@ -195,7 +209,7 @@
 
   template <typename Iterable,
 	    hb_requires (hb_is_iterable (Iterable))>
-  static unsigned total_size (const Iterable &iterable, unsigned *data_size = nullptr)
+  static unsigned total_size (const Iterable &iterable, unsigned *data_size = nullptr, unsigned min_off_size = 0)
   {
     auto it = + hb_iter (iterable);
     if (!it)
@@ -211,6 +225,7 @@
     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;
   }
@@ -274,8 +289,10 @@
   {
     TRACE_SANITIZE (this);
     return_trace (likely (c->check_struct (this) &&
+			  hb_barrier () &&
 			  (count == 0 || /* empty INDEX */
 			   (count < count + 1u &&
+			    hb_barrier () &&
 			    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))))));
@@ -412,6 +429,7 @@
     TRACE_SANITIZE (this);
     if (unlikely (!(c->check_struct (this))))
       return_trace (false);
+    hb_barrier ();
     if (unlikely (!c->check_array (fds, c->get_num_glyphs ())))
       return_trace (false);
 
@@ -438,7 +456,9 @@
   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;
@@ -456,15 +476,20 @@
   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);
@@ -559,6 +584,7 @@
     TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this)))
       return_trace (false);
+    hb_barrier ();
 
     switch (format)
     {
diff --git a/src/hb-ot-cff1-table.hh b/src/hb-ot-cff1-table.hh
index 1e81dcb..1bbd463 100644
--- a/src/hb-ot-cff1-table.hh
+++ b/src/hb-ot-cff1-table.hh
@@ -275,6 +275,7 @@
     TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this)))
       return_trace (false);
+    hb_barrier ();
 
     switch (table_format ())
     {
@@ -376,13 +377,13 @@
   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--;
     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);
     }
@@ -615,6 +616,7 @@
     TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this)))
       return_trace (false);
+    hb_barrier ();
 
     switch (format)
     {
@@ -761,9 +763,9 @@
   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;
 };
 
@@ -819,24 +821,24 @@
 	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;
@@ -911,7 +913,7 @@
   }
   void fini () { dict_values_t<VAL>::fini (); }
 
-  unsigned int      subrsOffset;
+  int                 subrsOffset;
   const CFF1Subrs    *localSubrs;
 };
 
@@ -946,7 +948,7 @@
 	env.clear_args ();
 	break;
       case OpCode_Subrs:
-	dictval.subrsOffset = env.argStack.pop_uint ();
+	dictval.subrsOffset = env.argStack.pop_int ();
 	env.clear_args ();
 	break;
 
@@ -988,7 +990,7 @@
 	break;
 
       case OpCode_Subrs:
-	dictval.subrsOffset = env.argStack.pop_uint ();
+	dictval.subrsOffset = env.argStack.pop_int ();
 	env.clear_args ();
 	break;
 
@@ -1055,6 +1057,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
+		  hb_barrier () &&
 		  likely (version.major == 1));
   }
 
@@ -1085,14 +1088,17 @@
       nameIndex = &cff->nameIndex (cff);
       if ((nameIndex == &Null (CFF1NameIndex)) || !nameIndex->sanitize (&sc))
         goto fail;
+      hb_barrier ();
 
-      topDictIndex = &StructAtOffset<CFF1TopDictIndex> (nameIndex, nameIndex->get_size ());
-      if ((topDictIndex == &Null (CFF1TopDictIndex)) || !topDictIndex->sanitize (&sc) || (topDictIndex->count == 0))
+      topDictIndex = &StructAtOffsetOrNull<CFF1TopDictIndex> (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)))   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)))   goto fail;
@@ -1102,17 +1108,17 @@
 	charset = &Null (Charset);
       else
       {
-	charset = &StructAtOffsetOrNull<Charset> (cff, topDict.CharsetOffset);
-	if (unlikely ((charset == &Null (Charset)) || !charset->sanitize (&sc, &num_charset_entries)))   goto fail;
+	charset = &StructAtOffsetOrNull<Charset> (cff, topDict.CharsetOffset, sc, &num_charset_entries);
+	if (unlikely (charset == &Null (Charset)))   goto fail;
       }
 
       fdCount = 1;
       if (is_CID ())
       {
-	fdArray = &StructAtOffsetOrNull<CFF1FDArray> (cff, topDict.FDArrayOffset);
-	fdSelect = &StructAtOffsetOrNull<CFF1FDSelect> (cff, topDict.FDSelectOffset);
-	if (unlikely ((fdArray == &Null (CFF1FDArray)) || !fdArray->sanitize (&sc) ||
-	    (fdSelect == &Null (CFF1FDSelect)) || !fdSelect->sanitize (&sc, fdArray->count)))
+	fdArray = &StructAtOffsetOrNull<CFF1FDArray> (cff, topDict.FDArrayOffset, sc);
+	fdSelect = &StructAtOffsetOrNull<CFF1FDSelect> (cff, topDict.FDSelectOffset, sc, fdArray->count);
+	if (unlikely (fdArray == &Null (CFF1FDArray) ||
+		      fdSelect == &Null (CFF1FDSelect)))
 	  goto fail;
 
 	fdCount = fdArray->count;
@@ -1132,22 +1138,18 @@
       {
 	if (!is_predef_encoding ())
 	{
-	  encoding = &StructAtOffsetOrNull<Encoding> (cff, topDict.EncodingOffset);
-	  if (unlikely ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc)))   goto fail;
+	  encoding = &StructAtOffsetOrNull<Encoding> (cff, topDict.EncodingOffset, sc);
+	  if (unlikely (encoding == &Null (Encoding)))   goto fail;
 	}
       }
 
-      stringIndex = &StructAtOffset<CFF1StringIndex> (topDictIndex, topDictIndex->get_size ());
-      if ((stringIndex == &Null (CFF1StringIndex)) || !stringIndex->sanitize (&sc))
+      stringIndex = &StructAtOffsetOrNull<CFF1StringIndex> (topDictIndex, topDictIndex->get_size (), sc);
+      if (stringIndex == &Null (CFF1StringIndex))
         goto fail;
 
-      globalSubrs = &StructAtOffset<CFF1Subrs> (stringIndex, stringIndex->get_size ());
-      if ((globalSubrs != &Null (CFF1Subrs)) && !globalSubrs->sanitize (&sc))
-        goto fail;
-
-      charStrings = &StructAtOffsetOrNull<CFF1CharStrings> (cff, topDict.charStringsOffset);
-
-      if ((charStrings == &Null (CFF1CharStrings)) || unlikely (!charStrings->sanitize (&sc)))
+      globalSubrs = &StructAtOffsetOrNull<CFF1Subrs> (stringIndex, stringIndex->get_size (), sc);
+      charStrings = &StructAtOffsetOrNull<CFF1CharStrings> (cff, topDict.charStringsOffset, sc);
+      if (charStrings == &Null (CFF1CharStrings))
         goto fail;
 
       num_glyphs = charStrings->count;
@@ -1166,6 +1168,7 @@
 	{
 	  hb_ubytes_t fontDictStr = (*fdArray)[i];
 	  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);
@@ -1175,17 +1178,13 @@
 	  font->init ();
 	  if (unlikely (!font_interp.interpret (*font)))   goto fail;
 	  PRIVDICTVAL *priv = &privateDicts[i];
-	  const hb_ubytes_t privDictStr = StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size);
-	  if (unlikely (!privDictStr.sanitize (&sc)))   goto fail;
+	  const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size);
 	  num_interp_env_t env2 (privDictStr);
 	  dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env2);
 	  priv->init ();
 	  if (unlikely (!priv_interp.interpret (*priv)))   goto fail;
 
-	  priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset);
-	  if (priv->localSubrs != &Null (CFF1Subrs) &&
-	      unlikely (!priv->localSubrs->sanitize (&sc)))
-	    goto fail;
+	  priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset, sc);
 	}
       }
       else  /* non-CID */
@@ -1193,17 +1192,14 @@
 	cff1_top_dict_values_t *font = &topDict;
 	PRIVDICTVAL *priv = &privateDicts[0];
 
-	const hb_ubytes_t privDictStr = StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size);
-	if (unlikely (!privDictStr.sanitize (&sc)))   goto fail;
+	const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size);
 	num_interp_env_t env (privDictStr);
 	dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env);
 	priv->init ();
 	if (unlikely (!priv_interp.interpret (*priv)))   goto fail;
 
-	priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset);
-	if (priv->localSubrs != &Null (CFF1Subrs) &&
-	    unlikely (!priv->localSubrs->sanitize (&sc)))
-	  goto fail;
+	priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset, sc);
+	hb_barrier ();
       }
 
       return;
@@ -1420,7 +1416,7 @@
       hb_sorted_vector_t<gname_t> *names = glyph_names.get_acquire ();
       if (unlikely (!names))
       {
-	names = (hb_sorted_vector_t<gname_t> *) hb_calloc (sizeof (hb_sorted_vector_t<gname_t>), 1);
+	names = (hb_sorted_vector_t<gname_t> *) hb_calloc (1, sizeof (hb_sorted_vector_t<gname_t>));
 	if (likely (names))
 	{
 	  names->init ();
diff --git a/src/hb-ot-cff2-table.hh b/src/hb-ot-cff2-table.hh
index af24bb9..4b3bdc9 100644
--- a/src/hb-ot-cff2-table.hh
+++ b/src/hb-ot-cff2-table.hh
@@ -90,6 +90,7 @@
     TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this)))
       return_trace (false);
+    hb_barrier ();
 
     switch (format)
     {
@@ -110,19 +111,22 @@
   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<CFF2VariationStore> (size_);
+    CFF2ItemVariationStore *dest = c->allocate_size<CFF2ItemVariationStore> (size_);
     if (unlikely (!dest)) return_trace (false);
     hb_memcpy (dest, varStore, size_);
     return_trace (true);
@@ -131,9 +135,9 @@
   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 +150,8 @@
   }
   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 +169,11 @@
 	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 +241,7 @@
   }
   void fini () { dict_values_t<VAL>::fini (); }
 
-  unsigned int      subrsOffset;
+  int                subrsOffset;
   const CFF2Subrs   *localSubrs;
   unsigned int      ivs;
 };
@@ -291,7 +295,7 @@
 	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:
@@ -340,7 +344,7 @@
 	return;
 
       case OpCode_Subrs:
-	dictval.subrsOffset = env.argStack.pop_uint ();
+	dictval.subrsOffset = env.argStack.pop_int ();
 	env.clear_args ();
 	break;
 
@@ -384,6 +388,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
+		  hb_barrier () &&
 		  likely (version.major == 2));
   }
 
@@ -414,23 +419,22 @@
       { /* 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<CFF2Subrs> (cff2, cff2->topDict + cff2->topDictSize);
-      varStore = &StructAtOffsetOrNull<CFF2VariationStore> (cff2, topDict.vstoreOffset);
-      charStrings = &StructAtOffsetOrNull<CFF2CharStrings> (cff2, topDict.charStringsOffset);
-      fdArray = &StructAtOffsetOrNull<CFF2FDArray> (cff2, topDict.FDArrayOffset);
-      fdSelect = &StructAtOffsetOrNull<CFF2FDSelect> (cff2, topDict.FDSelectOffset);
+      globalSubrs = &StructAtOffsetOrNull<CFF2Subrs> (cff2, cff2->topDict + cff2->topDictSize, sc);
+      varStore = &StructAtOffsetOrNull<CFF2ItemVariationStore> (cff2, topDict.vstoreOffset, sc);
+      charStrings = &StructAtOffsetOrNull<CFF2CharStrings> (cff2, topDict.charStringsOffset, sc);
+      fdArray = &StructAtOffsetOrNull<CFF2FDArray> (cff2, topDict.FDArrayOffset, sc);
+      fdSelect = &StructAtOffsetOrNull<CFF2FDSelect> (cff2, topDict.FDSelectOffset, sc, fdArray->count);
 
-      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)))))
+      if (charStrings == &Null (CFF2CharStrings) ||
+	  globalSubrs == &Null (CFF2Subrs) ||
+	  fdArray == &Null (CFF2FDArray))
         goto fail;
 
       num_glyphs = charStrings->count;
@@ -446,6 +450,7 @@
       {
 	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);
@@ -454,17 +459,13 @@
 	font->init ();
 	if (unlikely (!font_interp.interpret (*font))) goto fail;
 
-	const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size);
-	if (unlikely (!privDictStr.sanitize (&sc))) goto fail;
+	const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size);
 	cff2_priv_dict_interp_env_t env2 (privDictStr);
 	dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t> priv_interp (env2);
 	privateDicts[i].init ();
 	if (unlikely (!priv_interp.interpret (privateDicts[i]))) goto fail;
 
-	privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (&privDictStr[0], privateDicts[i].subrsOffset);
-	if (privateDicts[i].localSubrs != &Null (CFF2Subrs) &&
-	  unlikely (!privateDicts[i].localSubrs->sanitize (&sc)))
-	  goto fail;
+	privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (&privDictStr[0], privateDicts[i].subrsOffset, sc);
       }
 
       return;
@@ -499,7 +500,7 @@
     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;
diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh
index 30401b1..64d2b13 100644
--- a/src/hb-ot-cmap-table.hh
+++ b/src/hb-ot-cmap-table.hh
@@ -41,6 +41,30 @@
 
 namespace OT {
 
+static inline uint8_t unicode_to_macroman (hb_codepoint_t u)
+{
+  uint16_t mapping[] = {
+    0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1,
+    0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8,
+    0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3,
+    0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC,
+    0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF,
+    0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8,
+    0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211,
+    0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x00E6, 0x00F8,
+    0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB,
+    0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153,
+    0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA,
+    0x00FF, 0x0178, 0x2044, 0x20AC, 0x2039, 0x203A, 0xFB01, 0xFB02,
+    0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1,
+    0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4,
+    0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC,
+    0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7
+  };
+  uint16_t *c = hb_bsearch (u, mapping, ARRAY_LENGTH (mapping), sizeof (mapping[0]),
+			    _hb_cmp_operator<uint16_t, uint16_t>);
+  return c ? (c - mapping) + 0x7F : 0;
+}
 
 struct CmapSubtableFormat0
 {
@@ -556,6 +580,7 @@
     TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this)))
       return_trace (false);
+    hb_barrier ();
 
     if (unlikely (!c->check_range (this, length)))
     {
@@ -742,10 +767,11 @@
 			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.
@@ -754,7 +780,7 @@
       last_end = end;
 
 
-      hb_codepoint_t gid = this->groups[i].glyphID;
+      hb_codepoint_t gid = this->groups.arrayZ[i].glyphID;
       if (!gid)
       {
         if (T::formatNumber == 13) continue;
@@ -767,9 +793,9 @@
 
       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 += T::increment;
       }
@@ -1427,6 +1453,7 @@
   {
     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));
@@ -1462,8 +1489,11 @@
     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;
   }
 
@@ -1811,9 +1841,13 @@
                                          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;
 
@@ -1838,6 +1872,20 @@
     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);
   }
@@ -1849,8 +1897,8 @@
     accelerator_t (hb_face_t *face)
     {
       this->table = hb_sanitize_context_t ().reference_table<cmap> (face);
-      bool symbol;
-      this->subtable = table->find_best_subtable (&symbol);
+      bool symbol, mac, macroman;
+      this->subtable = table->find_best_subtable (&symbol, &mac, &macroman);
       this->subtable_uvs = &Null (CmapSubtableFormat14);
       {
 	const CmapSubtable *st = table->find_subtable (0, 5);
@@ -1859,6 +1907,7 @@
       }
 
       this->get_glyph_data = subtable;
+#ifndef HB_NO_CMAP_LEGACY_SUBTABLES
       if (unlikely (symbol))
       {
 	switch ((unsigned) face->table.OS2->get_font_page ()) {
@@ -1878,7 +1927,16 @@
 	  break;
 	}
       }
+      else if (unlikely (macroman))
+      {
+	this->get_glyph_funcZ = get_glyph_from_macroman<CmapSubtable>;
+      }
+      else if (unlikely (mac))
+      {
+	this->get_glyph_funcZ = get_glyph_from_ascii<CmapSubtable>;
+      }
       else
+#endif
       {
 	switch (subtable->u.format) {
 	/* Accelerate format 4 and format 12. */
@@ -1921,7 +1979,7 @@
 			    hb_codepoint_t *glyph,
 			    cache_t *cache = nullptr) const
     {
-      if (unlikely (!this->get_glyph_funcZ)) return 0;
+      if (unlikely (!this->get_glyph_funcZ)) return false;
       return _cached_get (unicode, glyph, cache);
     }
 
@@ -2003,6 +2061,28 @@
       return false;
     }
 
+    template <typename Type>
+    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 <typename Type>
+    HB_INTERNAL static bool get_glyph_from_macroman (const void *obj,
+						     hb_codepoint_t codepoint,
+						     hb_codepoint_t *glyph)
+    {
+      if (get_glyph_from_ascii<Type> (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<const CmapSubtable> subtable;
     hb_nonnull_ptr_t<const CmapSubtableFormat14> subtable_uvs;
@@ -2032,34 +2112,13 @@
     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));
   }
diff --git a/src/hb-ot-face-table-list.hh b/src/hb-ot-face-table-list.hh
index b552dfd..db1c554 100644
--- a/src/hb-ot-face-table-list.hh
+++ b/src/hb-ot-face-table-list.hh
@@ -100,7 +100,7 @@
 
 /* Legacy kern. */
 #ifndef HB_NO_OT_KERN
-HB_OT_CORE_TABLE (OT, kern)
+HB_OT_ACCELERATOR (OT, kern)
 #endif
 
 /* OpenType shaping. */
@@ -118,9 +118,9 @@
 
 /* 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)
diff --git a/src/hb-ot-face.cc b/src/hb-ot-face.cc
index 2243ee0..b0c9279 100644
--- a/src/hb-ot-face.cc
+++ b/src/hb-ot-face.cc
@@ -41,6 +41,8 @@
 #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/src/hb-ot-font.cc b/src/hb-ot-font.cc
index b3677c6..1da869d 100644
--- a/src/hb-ot-font.cc
+++ b/src/hb-ot-font.cc
@@ -208,12 +208,12 @@
 
 #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
 
@@ -277,7 +277,7 @@
   }
 
 #if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
-  OT::VariationStore::destroy_cache (varStore_cache);
+  OT::ItemVariationStore::destroy_cache (varStore_cache);
 #endif
 
   if (font->x_strength && !font->embolden_in_place)
@@ -313,10 +313,10 @@
   {
 #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++)
@@ -327,7 +327,7 @@
     }
 
 #if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
-    OT::VariationStore::destroy_cache (varStore_cache);
+    OT::ItemVariationStore::destroy_cache (varStore_cache);
 #endif
   }
   else
diff --git a/src/hb-ot-hdmx-table.hh b/src/hb-ot-hdmx-table.hh
index cbcf6f5..8582dbe 100644
--- a/src/hb-ot-hdmx-table.hh
+++ b/src/hb-ot-hdmx-table.hh
@@ -71,6 +71,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (likely (c->check_struct (this) &&
+			  hb_barrier () &&
 			  c->check_range (this, sizeDeviceRecord)));
   }
 
@@ -152,6 +153,7 @@
   {
     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 &&
diff --git a/src/hb-ot-head-table.hh b/src/hb-ot-head-table.hh
index 770cf52..4cb6c15 100644
--- a/src/hb-ot-head-table.hh
+++ b/src/hb-ot-head-table.hh
@@ -103,6 +103,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
+		  hb_barrier () &&
 		  version.major == 1 &&
 		  magicNumber == 0x5F0F3CF5u);
   }
diff --git a/src/hb-ot-hhea-table.hh b/src/hb-ot-hhea-table.hh
index d9c9bd3..27becfd 100644
--- a/src/hb-ot-hhea-table.hh
+++ b/src/hb-ot-hhea-table.hh
@@ -50,7 +50,9 @@
   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/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh
index 89640b4..e259b33 100644
--- a/src/hb-ot-hmtx-table.hh
+++ b/src/hb-ot-hmtx-table.hh
@@ -145,6 +145,29 @@
         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<int> (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<int> (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<int> (roundf (OS2.sTypoLineGap +
+                                                     MVAR.get_var (HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP,
+                                                                   c->plan->normalized_coords.arrayZ,
+                                                                   c->plan->normalized_coords.length)));
+        }
+      }
     }
 #endif
 
@@ -374,7 +397,7 @@
 
     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);
 
@@ -387,7 +410,8 @@
 									font->coords, font->num_coords,
 									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
diff --git a/src/hb-ot-kern-table.hh b/src/hb-ot-kern-table.hh
index ffa11bc..b87ac8f 100644
--- a/src/hb-ot-kern-table.hh
+++ b/src/hb-ot-kern-table.hh
@@ -79,12 +79,23 @@
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
+		  hb_barrier () &&
 		  c->check_range (kernValueZ,
 				  kernValueCount * sizeof (FWORD) +
 				  glyphCount * 2 +
 				  leftClassCount * rightClassCount));
   }
 
+  template <typename set_t>
+  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;
@@ -134,22 +145,36 @@
     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<Ts> (ds)...) : c->default_return_value ());
+    case 1:	return_trace (c->dispatch (u.format1, std::forward<Ts> (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<Ts> (ds)...) : c->default_return_value ());
+    case 3:	return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
 #endif
     default:	return_trace (c->default_return_value ());
     }
   }
 
+  template <typename set_t>
+  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));
   }
@@ -316,8 +341,9 @@
     }
   }
 
-  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, typename ...Ts>
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
@@ -337,9 +363,45 @@
   {
     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: return u.ot.create_accelerator_data (num_glyphs);
+#ifndef HB_NO_AAT_SHAPE
+    case 1: 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<kern> (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<kern> table;
+    AAT::kern_accelerator_data_t accel_data;
+  };
+
   protected:
   union {
   HBUINT32		version32;
@@ -353,6 +415,10 @@
   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/src/hb-ot-layout-base-table.hh b/src/hb-ot-layout-base-table.hh
index 2b7e9e4..5629090 100644
--- a/src/hb-ot-layout-base-table.hh
+++ b/src/hb-ot-layout-base-table.hh
@@ -46,6 +46,12 @@
     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 @@
     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 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 @@
 	 : 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<unsigned, int> *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,7 +168,7 @@
   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) {
@@ -131,10 +179,32 @@
     }
   }
 
+  void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const
+  {
+    switch (u.format) {
+    case 3: u.format3.collect_variation_indices (varidx_set);
+    default:return;
+    }
+  }
+
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format);
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+    case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
   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));
@@ -160,12 +230,37 @@
 
   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);
@@ -205,6 +300,39 @@
     }
   }
 
+  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);
@@ -239,6 +367,26 @@
     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);
@@ -267,7 +415,22 @@
 
   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
   {
@@ -290,7 +453,7 @@
   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
@@ -299,6 +462,35 @@
   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
   {
     TRACE_SANITIZE (this);
@@ -331,9 +523,31 @@
 
   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 @@
     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);
@@ -421,6 +662,20 @@
     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);
@@ -452,8 +707,77 @@
   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<ItemVariationStore>> (Offset32To<ItemVariationStore>::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,
@@ -486,7 +810,7 @@
 					   &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;
@@ -496,6 +820,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (likely (c->check_struct (this) &&
+			  hb_barrier () &&
 			  likely (version.major == 1) &&
 			  hAxis.sanitize (c, this) &&
 			  vAxis.sanitize (c, this) &&
@@ -508,7 +833,7 @@
 				 * of BASE table (may be NULL) */
   Offset16To<Axis>vAxis;		/* Offset to vertical Axis table, from beginning
 				 * of BASE table (may be NULL) */
-  Offset32To<VariationStore>
+  Offset32To<ItemVariationStore>
 		varStore;	/* Offset to the table of Item Variation
 				 * Store--from beginning of BASE
 				 * header (may be NULL).  Introduced
diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh
index e869d8e..65c8309 100644
--- a/src/hb-ot-layout-common.hh
+++ b/src/hb-ot-layout-common.hh
@@ -64,7 +64,7 @@
   const hb_hashmap_t<hb_tag_t, Triple> *axes_location;
   hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *record_cond_idx_map;
   hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map;
-  bool& insert_catch_all_feature_variation_record;
+  hb_set_t& catch_all_record_feature_idxes;
 
   // not stored in subset_plan
   hb_set_t *feature_indices;
@@ -142,6 +142,8 @@
   const hb_map_t *feature_index_map;
   const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map;
   hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map;
+  const hb_set_t *catch_all_record_feature_idxes;
+  const hb_hashmap_t<unsigned, hb_pair_t<const void*, const void*>> *feature_idx_tag_map;
 
   unsigned cur_script_index;
   unsigned cur_feature_var_record_idx;
@@ -164,6 +166,8 @@
       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
     {
@@ -172,6 +176,8 @@
       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;
     }
   }
 
@@ -182,7 +188,7 @@
   unsigned lookup_index_count;
 };
 
-struct VariationStore;
+struct ItemVariationStore;
 struct hb_collect_variation_indices_context_t :
        hb_dispatch_context_t<hb_collect_variation_indices_context_t>
 {
@@ -454,6 +460,7 @@
   {
     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
@@ -820,6 +827,7 @@
     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!
@@ -838,6 +846,7 @@
     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') &&
@@ -900,7 +909,8 @@
   {
     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 */
@@ -1371,10 +1381,20 @@
 
     if (lookupFlag & LookupFlag::UseMarkFilteringSet)
     {
-      if (unlikely (!c->serializer->extend (out))) return_trace (false);
       const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
-      HBUINT16 &outMarkFilteringSet = StructAfter<HBUINT16> (out->subTable);
-      outMarkFilteringSet = markFilteringSet;
+      hb_codepoint_t *idx;
+      if (!c->plan->used_mark_sets_map.has (markFilteringSet, &idx))
+      {
+        unsigned new_flag = lookupFlag;
+        new_flag &= ~LookupFlag::UseMarkFilteringSet;
+        out->lookupFlag = new_flag;
+      }
+      else
+      {
+        if (unlikely (!c->serializer->extend (out))) return_trace (false);
+        HBUINT16 &outMarkFilteringSet = StructAfter<HBUINT16> (out->subTable);
+        outMarkFilteringSet = *idx;
+      }
     }
 
     // Always keep the lookup even if it's empty. The rest of layout subsetting depends on lookup
@@ -1391,6 +1411,7 @@
   {
     TRACE_SANITIZE (this);
     if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false);
+    hb_barrier ();
 
     unsigned subtables = get_subtable_count ();
     if (unlikely (!c->visit_subtables (subtables))) return_trace (false);
@@ -1406,6 +1427,8 @@
 
     if (unlikely (get_type () == TSubTable::Extension && !c->get_edit_count ()))
     {
+      hb_barrier ();
+
       /* The spec says all subtables of an Extension lookup should
        * have the same type, which shall not be the Extension type
        * itself (but we already checked for that).
@@ -2156,6 +2179,7 @@
   {
     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));
@@ -2534,7 +2558,9 @@
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && axesZ.sanitize (c, axisCount * regionCount));
+    return_trace (c->check_struct (this) &&
+		  hb_barrier () &&
+		  axesZ.sanitize (c, axisCount * regionCount));
   }
 
   bool serialize (hb_serialize_context_t *c,
@@ -2615,7 +2641,7 @@
       float max_val = axis_region->endCoord.to_float ();
 
       if (def_val != 0.f)
-        axis_tuples.set (*axis_tag, Triple (min_val, def_val, max_val));
+        axis_tuples.set (*axis_tag, Triple ((double) min_val, (double) def_val, (double) max_val));
       axis_region++;
     }
     return !axis_tuples.in_error ();
@@ -2728,6 +2754,7 @@
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
 		  regionIndices.sanitize (c) &&
+		  hb_barrier () &&
 		  wordCount () <= regionIndices.len &&
 		  c->check_range (get_delta_bytes (),
 				  itemCount,
@@ -3009,7 +3036,7 @@
   DEFINE_SIZE_ARRAY (6, regionIndices);
 };
 
-struct VariationStore
+struct ItemVariationStore
 {
   friend struct item_variations_t;
   using cache_t = VarRegionList::cache_t;
@@ -3077,6 +3104,7 @@
 
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
+		  hb_barrier () &&
 		  format == 1 &&
 		  regions.sanitize (c, this) &&
 		  dataSets.sanitize (c, this));
@@ -3113,7 +3141,7 @@
   }
 
   bool serialize (hb_serialize_context_t *c,
-		  const VariationStore *src,
+		  const ItemVariationStore *src,
 		  const hb_array_t <const hb_inc_bimap_t> &inner_maps)
   {
     TRACE_SERIALIZE (this);
@@ -3169,7 +3197,7 @@
     return_trace (true);
   }
 
-  VariationStore *copy (hb_serialize_context_t *c) const
+  ItemVariationStore *copy (hb_serialize_context_t *c) const
   {
     TRACE_SERIALIZE (this);
     auto *out = c->start_embed (this);
@@ -3180,6 +3208,8 @@
     for (unsigned i = 0; i < count; i++)
     {
       hb_inc_bimap_t *map = inner_maps.push ();
+      if (!c->propagate_error(inner_maps))
+        return_trace(nullptr);
       auto &data = this+dataSets[i];
 
       unsigned itemCount = data.get_item_count ();
@@ -3199,7 +3229,7 @@
     return_trace (false);
 #endif
 
-    VariationStore *varstore_prime = c->serializer->start_embed<VariationStore> ();
+    ItemVariationStore *varstore_prime = c->serializer->start_embed<ItemVariationStore> ();
     if (unlikely (!varstore_prime)) return_trace (false);
 
     varstore_prime->serialize (c->serializer, this, inner_maps);
@@ -3298,19 +3328,19 @@
       return_trace (false);
 
     const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location = c->plan->axes_location;
-    Triple axis_limit{-1.f, 0.f, 1.f};
+    Triple axis_limit{-1.0, 0.0, 1.0};
     Triple *normalized_limit;
     if (normalized_axes_location.has (*axis_tag, &normalized_limit))
       axis_limit = *normalized_limit;
 
     const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances = c->plan->axes_triple_distances;
-    TripleDistances axis_triple_distances{1.f, 1.f};
+    TripleDistances axis_triple_distances{1.0, 1.0};
     TripleDistances *triple_dists;
     if (axes_triple_distances.has (*axis_tag, &triple_dists))
       axis_triple_distances = *triple_dists;
 
-    float normalized_min = renormalizeValue (filterRangeMinValue.to_float (), axis_limit, axis_triple_distances, false);
-    float normalized_max = renormalizeValue (filterRangeMaxValue.to_float (), axis_limit, axis_triple_distances, false);
+    float normalized_min = renormalizeValue ((double) filterRangeMinValue.to_float (), axis_limit, axis_triple_distances, false);
+    float normalized_max = renormalizeValue ((double) filterRangeMaxValue.to_float (), axis_limit, axis_triple_distances, false);
     out->filterRangeMinValue.set_float (normalized_min);
     out->filterRangeMaxValue.set_float (normalized_max);
 
@@ -3328,10 +3358,14 @@
 
     hb_tag_t axis_tag = c->axes_index_tag_map->get (axisIndex);
 
-    Triple axis_range (-1.f, 0.f, 1.f);
+    Triple axis_range (-1.0, 0.0, 1.0);
     Triple *axis_limit;
+    bool axis_set_by_user = false;
     if (c->axes_location->has (axis_tag, &axis_limit))
+    {
       axis_range = *axis_limit;
+      axis_set_by_user = true;
+    }
 
     float axis_min_val = axis_range.minimum;
     float axis_default_val = axis_range.middle;
@@ -3350,8 +3384,7 @@
       return DROP_RECORD_WITH_VAR;
 
     //condition met and axis pinned, drop the condition
-    if (c->axes_location->has (axis_tag) &&
-        c->axes_location->get (axis_tag).is_point ())
+    if (axis_set_by_user && axis_range.is_point ())
       return DROP_COND_WITH_VAR;
 
     if (filter_max_val != axis_max_val || filter_min_val != axis_min_val)
@@ -3365,7 +3398,6 @@
       condition_map->set (axisIndex, val);
       return KEEP_COND_WITH_VAR;
     }
-
     return KEEP_RECORD_WITH_VAR;
   }
 
@@ -3424,6 +3456,7 @@
   {
     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);
@@ -3497,12 +3530,15 @@
   }
 
   bool subset (hb_subset_context_t *c,
-               hb_subset_layout_context_t *l) const
+               hb_subset_layout_context_t *l,
+               bool insert_catch_all) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->start_embed (this);
     if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
 
+    if (insert_catch_all) return_trace (true);
+
     hb_set_t *retained_cond_set = nullptr;
     if (l->feature_record_cond_idx_map != nullptr)
       retained_cond_set = l->feature_record_cond_idx_map->get (l->cur_feature_var_record_idx);
@@ -3548,27 +3584,51 @@
   }
 
   void collect_feature_substitutes_with_variations (hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
+                                                    hb_set_t& catch_all_record_feature_idxes,
                                                     const hb_set_t *feature_indices,
                                                     const void *base) const
   {
     if (feature_indices->has (featureIndex))
+    {
       feature_substitutes_map->set (featureIndex, &(base+feature));
+      catch_all_record_feature_idxes.add (featureIndex);
+    }
+  }
+
+  bool serialize (hb_subset_layout_context_t *c,
+                  unsigned feature_index,
+                  const Feature *f, const Tag *tag)
+  {
+    TRACE_SERIALIZE (this);
+    hb_serialize_context_t *s = c->subset_context->serializer;
+    if (unlikely (!s->extend_min (this))) return_trace (false);
+
+    uint32_t *new_feature_idx;
+    if (!c->feature_index_map->has (feature_index, &new_feature_idx))
+      return_trace (false);
+
+    if (!s->check_assign (featureIndex, *new_feature_idx, HB_SERIALIZE_ERROR_INT_OVERFLOW))
+      return_trace (false);
+
+    s->push ();
+    bool ret = f->subset (c->subset_context, c, tag);
+    if (ret) s->add_link (feature, s->pop_pack ());
+    else s->pop_discard ();
+
+    return_trace (ret);
   }
 
   bool subset (hb_subset_layout_context_t *c, const void *base) const
   {
     TRACE_SUBSET (this);
-    if (!c->feature_index_map->has (featureIndex) ||
-        c->feature_substitutes_map->has (featureIndex)) {
-      // Feature that is being substituted is not being retained, so we don't
-      // need this.
+    uint32_t *new_feature_index;
+    if (!c->feature_index_map->has (featureIndex, &new_feature_index))
       return_trace (false);
-    }
 
     auto *out = c->subset_context->serializer->embed (this);
     if (unlikely (!out)) return_trace (false);
 
-    out->featureIndex = c->feature_index_map->get (featureIndex);
+    out->featureIndex = *new_feature_index;
     return_trace (out->feature.serialize_subset (c->subset_context, feature, base, c));
   }
 
@@ -3600,16 +3660,10 @@
   }
 
   void collect_lookups (const hb_set_t *feature_indexes,
-			const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
 			hb_set_t       *lookup_indexes /* OUT */) const
   {
     + hb_iter (substitutions)
     | hb_filter (feature_indexes, &FeatureTableSubstitutionRecord::featureIndex)
-    | hb_filter ([feature_substitutes_map] (const FeatureTableSubstitutionRecord& record)
-                 {
-                   if (feature_substitutes_map == nullptr) return true;
-                   return !feature_substitutes_map->has (record.featureIndex);
-                 })
     | hb_apply ([this, lookup_indexes] (const FeatureTableSubstitutionRecord& r)
 		{ r.collect_lookups (this, lookup_indexes); })
     ;
@@ -3634,11 +3688,14 @@
   void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
   {
     for (const FeatureTableSubstitutionRecord& record : substitutions)
-      record.collect_feature_substitutes_with_variations (c->feature_substitutes_map, c->feature_indices, this);
+      record.collect_feature_substitutes_with_variations (c->feature_substitutes_map,
+                                                          c->catch_all_record_feature_idxes,
+                                                          c->feature_indices, this);
   }
 
   bool subset (hb_subset_context_t        *c,
-	       hb_subset_layout_context_t *l) const
+	       hb_subset_layout_context_t *l,
+               bool insert_catch_all) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->start_embed (*this);
@@ -3647,6 +3704,22 @@
     out->version.major = version.major;
     out->version.minor = version.minor;
 
+    if (insert_catch_all)
+    {
+      for (unsigned feature_index : *(l->catch_all_record_feature_idxes))
+      {
+        hb_pair_t<const void*, const void*> *p;
+        if (!l->feature_idx_tag_map->has (feature_index, &p))
+          return_trace (false);
+        auto *o = out->substitutions.serialize_append (c->serializer);
+        if (!o->serialize (l, feature_index,
+                           reinterpret_cast<const Feature*> (p->first),
+                           reinterpret_cast<const Tag*> (p->second)))
+          return_trace (false);
+      }
+      return_trace (true);
+    }
+
     + substitutions.iter ()
     | hb_apply (subset_record_array (l, &(out->substitutions), this))
     ;
@@ -3658,6 +3731,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (version.sanitize (c) &&
+		  hb_barrier () &&
 		  likely (version.major == 1) &&
 		  substitutions.sanitize (c, this));
   }
@@ -3676,10 +3750,9 @@
 
   void collect_lookups (const void     *base,
 			const hb_set_t *feature_indexes,
-			const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
 			hb_set_t       *lookup_indexes /* OUT */) const
   {
-    return (base+substitutions).collect_lookups (feature_indexes, feature_substitutes_map, lookup_indexes);
+    return (base+substitutions).collect_lookups (feature_indexes, lookup_indexes);
   }
 
   void closure_features (const void     *base,
@@ -3705,14 +3778,15 @@
     }
   }
 
-  bool subset (hb_subset_layout_context_t *c, const void *base) const
+  bool subset (hb_subset_layout_context_t *c, const void *base,
+               bool insert_catch_all = false) const
   {
     TRACE_SUBSET (this);
     auto *out = c->subset_context->serializer->embed (this);
     if (unlikely (!out)) return_trace (false);
 
-    out->conditions.serialize_subset (c->subset_context, conditions, base, c);
-    out->substitutions.serialize_subset (c->subset_context, substitutions, base, c);
+    out->conditions.serialize_subset (c->subset_context, conditions, base, c, insert_catch_all);
+    out->substitutions.serialize_subset (c->subset_context, substitutions, base, c, insert_catch_all);
 
     return_trace (true);
   }
@@ -3771,9 +3845,8 @@
       if (c->universal)
         break;
     }
-    if (c->variation_applied && !c->universal &&
-        !c->record_cond_idx_map->is_empty ())
-      c->insert_catch_all_feature_variation_record = true;
+    if (c->universal || c->record_cond_idx_map->is_empty ())
+      c->catch_all_record_feature_idxes.reset ();
   }
 
   FeatureVariations* copy (hb_serialize_context_t *c) const
@@ -3783,11 +3856,17 @@
   }
 
   void collect_lookups (const hb_set_t *feature_indexes,
-			const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
+			const hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map,
 			hb_set_t       *lookup_indexes /* OUT */) const
   {
-    for (const FeatureVariationRecord& r : varRecords)
-      r.collect_lookups (this, feature_indexes, feature_substitutes_map, lookup_indexes);
+    unsigned count = varRecords.len;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      if (feature_record_cond_idx_map &&
+          !feature_record_cond_idx_map->has (i))
+        continue;
+      varRecords[i].collect_lookups (this, feature_indexes, lookup_indexes);
+    }
   }
 
   void closure_features (const hb_map_t *lookup_indexes,
@@ -3832,6 +3911,13 @@
       l->cur_feature_var_record_idx = i;
       subset_record_array (l, &(out->varRecords), this) (varRecords[i]);
     }
+
+    if (out->varRecords.len && !l->catch_all_record_feature_idxes->is_empty ())
+    {
+      bool insert_catch_all_record = true;
+      subset_record_array (l, &(out->varRecords), this, insert_catch_all_record) (varRecords[0]);
+    }
+
     return_trace (bool (out->varRecords));
   }
 
@@ -3839,6 +3925,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (version.sanitize (c) &&
+		  hb_barrier () &&
 		  likely (version.major == 1) &&
 		  varRecords.sanitize (c, this));
   }
@@ -3945,13 +4032,13 @@
   private:
 
   hb_position_t get_x_delta (hb_font_t *font,
-			     const VariationStore &store,
-			     VariationStore::cache_t *store_cache = nullptr) const
+			     const ItemVariationStore &store,
+			     ItemVariationStore::cache_t *store_cache = nullptr) const
   { return font->em_scalef_x (get_delta (font, store, store_cache)); }
 
   hb_position_t get_y_delta (hb_font_t *font,
-			     const VariationStore &store,
-			     VariationStore::cache_t *store_cache = nullptr) const
+			     const ItemVariationStore &store,
+			     ItemVariationStore::cache_t *store_cache = nullptr) const
   { return font->em_scalef_y (get_delta (font, store, store_cache)); }
 
   VariationDevice* copy (hb_serialize_context_t *c,
@@ -3985,10 +4072,10 @@
   private:
 
   float get_delta (hb_font_t *font,
-		   const VariationStore &store,
-		   VariationStore::cache_t *store_cache = nullptr) const
+		   const ItemVariationStore &store,
+		   ItemVariationStore::cache_t *store_cache = nullptr) const
   {
-    return store.get_delta (varIdx, font->coords, font->num_coords, (VariationStore::cache_t *) store_cache);
+    return store.get_delta (varIdx, font->coords, font->num_coords, (ItemVariationStore::cache_t *) store_cache);
   }
 
   protected:
@@ -4012,8 +4099,8 @@
 struct Device
 {
   hb_position_t get_x_delta (hb_font_t *font,
-			     const VariationStore &store=Null (VariationStore),
-			     VariationStore::cache_t *store_cache = nullptr) const
+			     const ItemVariationStore &store=Null (ItemVariationStore),
+			     ItemVariationStore::cache_t *store_cache = nullptr) const
   {
     switch (u.b.format)
     {
@@ -4030,8 +4117,8 @@
     }
   }
   hb_position_t get_y_delta (hb_font_t *font,
-			     const VariationStore &store=Null (VariationStore),
-			     VariationStore::cache_t *store_cache = nullptr) const
+			     const ItemVariationStore &store=Null (ItemVariationStore),
+			     ItemVariationStore::cache_t *store_cache = nullptr) const
   {
     switch (u.b.format)
     {
diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh
index 662ec9d..6b760b1 100644
--- a/src/hb-ot-layout-gsubgpos.hh
+++ b/src/hb-ot-layout-gsubgpos.hh
@@ -708,8 +708,8 @@
   recurse_func_t recurse_func = nullptr;
   const GDEF &gdef;
   const GDEF::accelerator_t &gdef_accel;
-  const VariationStore &var_store;
-  VariationStore::cache_t *var_store_cache;
+  const ItemVariationStore &var_store;
+  ItemVariationStore::cache_t *var_store_cache;
   hb_set_digest_t digest;
 
   hb_direction_t direction;
@@ -723,7 +723,6 @@
   bool auto_zwj = true;
   bool per_syllable = false;
   bool random = false;
-  uint32_t random_state = 1;
   unsigned new_syllables = (unsigned) -1;
 
   signed last_base = -1; // GPOS uses
@@ -766,7 +765,7 @@
   ~hb_ot_apply_context_t ()
   {
 #ifndef HB_NO_VAR
-    VariationStore::destroy_cache (var_store_cache);
+    ItemVariationStore::destroy_cache (var_store_cache);
 #endif
   }
 
@@ -788,8 +787,8 @@
   uint32_t random_number ()
   {
     /* http://www.cplusplus.com/reference/random/minstd_rand/ */
-    random_state = random_state * 48271 % 2147483647;
-    return random_state;
+    buffer->random_state = buffer->random_state * 48271 % 2147483647;
+    return buffer->random_state;
   }
 
   bool match_properties_mark (hb_codepoint_t  glyph,
@@ -1255,7 +1254,7 @@
 			 match_func_t match_func,
 			 const void *match_data,
 			 unsigned int *end_position,
-			 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
+			 unsigned int *match_positions,
 			 unsigned int *p_total_component_count = nullptr)
 {
   TRACE_APPLY (nullptr);
@@ -1379,7 +1378,7 @@
 }
 static inline bool ligate_input (hb_ot_apply_context_t *c,
 				 unsigned int count, /* Including the first glyph */
-				 const unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
+				 const unsigned int *match_positions, /* Including the first glyph */
 				 unsigned int match_end,
 				 hb_codepoint_t lig_glyph,
 				 unsigned int total_component_count)
@@ -1687,7 +1686,7 @@
 
 static inline void apply_lookup (hb_ot_apply_context_t *c,
 				 unsigned int count, /* Including the first glyph */
-				 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
+				 unsigned int *match_positions, /* Including the first glyph */
 				 unsigned int lookupCount,
 				 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
 				 unsigned int match_end)
@@ -1695,6 +1694,9 @@
   hb_buffer_t *buffer = c->buffer;
   int end;
 
+  unsigned int *match_positions_input = match_positions;
+  unsigned int match_positions_count = count;
+
   /* All positions are distance from beginning of *output* buffer.
    * Adjust. */
   {
@@ -1798,6 +1800,27 @@
     {
       if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
 	break;
+      if (unlikely (delta + count > match_positions_count))
+      {
+        unsigned new_match_positions_count = hb_max (delta + count, hb_max(match_positions_count, 4u) * 1.5);
+        if (match_positions == match_positions_input)
+	{
+	  match_positions = (unsigned int *) hb_malloc (new_match_positions_count * sizeof (match_positions[0]));
+	  if (unlikely (!match_positions))
+	    break;
+	  memcpy (match_positions, match_positions_input, count * sizeof (match_positions[0]));
+	  match_positions_count = new_match_positions_count;
+	}
+	else
+	{
+	  unsigned int *new_match_positions = (unsigned int *) hb_realloc (match_positions, new_match_positions_count * sizeof (match_positions[0]));
+	  if (unlikely (!new_match_positions))
+	    break;
+	  match_positions = new_match_positions;
+	  match_positions_count = new_match_positions_count;
+	}
+      }
+
     }
     else
     {
@@ -1821,6 +1844,9 @@
       match_positions[next] += delta;
   }
 
+  if (match_positions != match_positions_input)
+    hb_free (match_positions);
+
   (void) buffer->move_to (end);
 }
 
@@ -1921,8 +1947,18 @@
 				  const LookupRecord lookupRecord[],
 				  const ContextApplyLookupContext &lookup_context)
 {
+  if (unlikely (inputCount > HB_MAX_CONTEXT_LENGTH)) return false;
+  unsigned match_positions_stack[4];
+  unsigned *match_positions = match_positions_stack;
+  if (unlikely (inputCount > ARRAY_LENGTH (match_positions_stack)))
+  {
+    match_positions = (unsigned *) hb_malloc (hb_max (inputCount, 1u) * sizeof (match_positions[0]));
+    if (unlikely (!match_positions))
+      return false;
+  }
+
   unsigned match_end = 0;
-  unsigned match_positions[HB_MAX_CONTEXT_LENGTH];
+  bool ret = false;
   if (match_input (c,
 		   inputCount, input,
 		   lookup_context.funcs.match, lookup_context.match_data,
@@ -1933,13 +1969,18 @@
 		  inputCount, match_positions,
 		  lookupCount, lookupRecord,
 		  match_end);
-    return true;
+    ret = true;
   }
   else
   {
     c->buffer->unsafe_to_concat (c->buffer->idx, match_end);
-    return false;
+    ret = false;
   }
+
+  if (unlikely (match_positions != match_positions_stack))
+    hb_free (match_positions);
+
+  return ret;
 }
 
 template <typename Types>
@@ -2051,6 +2092,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
+		  hb_barrier () &&
 		  c->check_range (inputZ.arrayZ,
 				  inputZ.item_size * (inputCount ? inputCount - 1 : 0) +
 				  LookupRecord::static_size * lookupCount));
@@ -2826,6 +2868,7 @@
   {
     TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this))) return_trace (false);
+    hb_barrier ();
     unsigned int count = glyphCount;
     if (unlikely (!count)) return_trace (false); /* We want to access coverageZ[0] freely. */
     if (unlikely (!c->check_array (coverageZ.arrayZ, count))) return_trace (false);
@@ -3017,9 +3060,20 @@
 					const LookupRecord lookupRecord[],
 					const ChainContextApplyLookupContext &lookup_context)
 {
+  if (unlikely (inputCount > HB_MAX_CONTEXT_LENGTH)) return false;
+  unsigned match_positions_stack[4];
+  unsigned *match_positions = match_positions_stack;
+  if (unlikely (inputCount > ARRAY_LENGTH (match_positions_stack)))
+  {
+    match_positions = (unsigned *) hb_malloc (hb_max (inputCount, 1u) * sizeof (match_positions[0]));
+    if (unlikely (!match_positions))
+      return false;
+  }
+
+  unsigned start_index = c->buffer->out_len;
   unsigned end_index = c->buffer->idx;
   unsigned match_end = 0;
-  unsigned match_positions[HB_MAX_CONTEXT_LENGTH];
+  bool ret = true;
   if (!(match_input (c,
 		     inputCount, input,
 		     lookup_context.funcs.match[1], lookup_context.match_data[1],
@@ -3030,17 +3084,18 @@
 			   match_end, &end_index)))
   {
     c->buffer->unsafe_to_concat (c->buffer->idx, end_index);
-    return false;
+    ret = false;
+    goto done;
   }
 
-  unsigned start_index = c->buffer->out_len;
   if (!match_backtrack (c,
 			backtrackCount, backtrack,
 			lookup_context.funcs.match[0], lookup_context.match_data[0],
 			&start_index))
   {
     c->buffer->unsafe_to_concat_from_outbuffer (start_index, end_index);
-    return false;
+    ret = false;
+    goto done;
   }
 
   c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
@@ -3048,7 +3103,12 @@
 		inputCount, match_positions,
 		lookupCount, lookupRecord,
 		match_end);
-  return true;
+  done:
+
+  if (unlikely (match_positions != match_positions_stack))
+    hb_free (match_positions);
+
+  return ret;
 }
 
 template <typename Types>
@@ -3219,10 +3279,13 @@
     TRACE_SANITIZE (this);
     /* Hyper-optimized sanitized because this is really hot. */
     if (unlikely (!backtrack.len.sanitize (c))) return_trace (false);
+    hb_barrier ();
     const auto &input = StructAfter<decltype (inputX)> (backtrack);
     if (unlikely (!input.lenP1.sanitize (c))) return_trace (false);
+    hb_barrier ();
     const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
     if (unlikely (!lookahead.len.sanitize (c))) return_trace (false);
+    hb_barrier ();
     const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
     return_trace (likely (lookup.sanitize (c)));
   }
@@ -4121,11 +4184,14 @@
   {
     TRACE_SANITIZE (this);
     if (unlikely (!backtrack.sanitize (c, this))) return_trace (false);
+    hb_barrier ();
     const auto &input = StructAfter<decltype (inputX)> (backtrack);
     if (unlikely (!input.sanitize (c, this))) return_trace (false);
+    hb_barrier ();
     if (unlikely (!input.len)) return_trace (false); /* To be consistent with Context. */
     const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
     if (unlikely (!lookahead.sanitize (c, this))) return_trace (false);
+    hb_barrier ();
     const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
     return_trace (likely (lookup.sanitize (c)));
   }
@@ -4209,6 +4275,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
+		  hb_barrier () &&
 		  extensionLookupType != T::SubTable::Extension);
   }
 
@@ -4320,7 +4387,7 @@
 
     thiz->digest.init ();
     for (auto& subtable : hb_iter (thiz->subtables, count))
-      thiz->digest.add (subtable.digest);
+      thiz->digest.union_ (subtable.digest);
 
 #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
     thiz->cache_user_idx = c_accelerate_subtables.cache_user_idx;
@@ -4472,13 +4539,6 @@
       if (!c->subset_context->serializer->extend_min (&out->featureVars))
         return_trace (false);
 
-      // TODO(qxliu76): the current implementation doesn't correctly handle feature variations
-      //                that are dropped by instancing when the associated conditions don't trigger.
-      //                Since partial instancing isn't yet supported this isn't an issue yet but will
-      //                need to be fixed for partial instancing.
-
-
-
       // if all axes are pinned all feature vars are dropped.
       bool ret = !c->subset_context->plan->all_axes_pinned
                  && out->featureVars.serialize_subset (c->subset_context, featureVars, this, c);
@@ -4513,6 +4573,7 @@
   {
     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<TLookup> (c));
 #ifndef HB_NO_BEYOND_64K
@@ -4638,11 +4699,11 @@
   }
 
   void feature_variation_collect_lookups (const hb_set_t *feature_indexes,
-					  const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
+					  const hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map,
 					  hb_set_t       *lookup_indexes /* OUT */) const
   {
 #ifndef HB_NO_VAR
-    get_feature_variations ().collect_lookups (feature_indexes, feature_substitutes_map, lookup_indexes);
+    get_feature_variations ().collect_lookups (feature_indexes, feature_record_cond_idx_map, lookup_indexes);
 #endif
   }
 
diff --git a/src/hb-ot-layout-jstf-table.hh b/src/hb-ot-layout-jstf-table.hh
index a1c125b..0ba7eaa 100644
--- a/src/hb-ot-layout-jstf-table.hh
+++ b/src/hb-ot-layout-jstf-table.hh
@@ -214,6 +214,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (version.sanitize (c) &&
+		  hb_barrier () &&
 		  likely (version.major == 1) &&
 		  scriptList.sanitize (c, this));
   }
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index a4c13ab..613c97f 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -87,7 +87,7 @@
 bool
 hb_ot_layout_has_kerning (hb_face_t *face)
 {
-  return face->table.kern->has_data ();
+  return face->table.kern->table->has_data ();
 }
 
 /**
@@ -103,7 +103,7 @@
 bool
 hb_ot_layout_has_machine_kerning (hb_face_t *face)
 {
-  return face->table.kern->has_state_machine ();
+  return face->table.kern->table->has_state_machine ();
 }
 
 /**
@@ -123,7 +123,7 @@
 bool
 hb_ot_layout_has_cross_kerning (hb_face_t *face)
 {
-  return face->table.kern->has_cross_stream ();
+  return face->table.kern->table->has_cross_stream ();
 }
 
 void
@@ -132,7 +132,7 @@
 		   hb_buffer_t  *buffer)
 {
   hb_blob_t *blob = font->face->table.kern.get_blob ();
-  const AAT::kern& kern = *blob->as<AAT::kern> ();
+  const auto& kern = *font->face->table.kern;
 
   AAT::hb_aat_apply_context_t c (plan, font, buffer, blob);
 
diff --git a/src/hb-ot-math-table.hh b/src/hb-ot-math-table.hh
index b11da46..5839059 100644
--- a/src/hb-ot-math-table.hh
+++ b/src/hb-ot-math-table.hh
@@ -333,6 +333,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
+		  hb_barrier () &&
 		  c->check_array (mathValueRecordsZ.arrayZ, 2 * heightCount + 1) &&
 		  sanitize_math_value_records (c));
   }
@@ -343,27 +344,20 @@
     const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount;
     int sign = font->y_scale < 0 ? -1 : +1;
 
-    /* The description of the MathKern table is a ambiguous, but interpreting
-     * "between the two heights found at those indexes" for 0 < i < len as
-     *
-     *   correctionHeight[i-1] < correction_height <= correctionHeight[i]
-     *
-     * makes the result consistent with the limit cases and we can just use the
-     * binary search algorithm of std::upper_bound:
+    /* According to OpenType spec (v1.9), except for the boundary cases, the index
+     * chosen for kern value should be i such that
+     *    correctionHeight[i-1] <= correction_height < correctionHeight[i]
+     * We can use the binary search algorithm of std::upper_bound(). Or, we can
+     * use the internal hb_bsearch_impl.
      */
-    unsigned int i = 0;
-    unsigned int count = heightCount;
-    while (count > 0)
-    {
-      unsigned int half = count / 2;
-      hb_position_t height = correctionHeight[i + half].get_y_value (font, this);
-      if (sign * height < sign * correction_height)
-      {
-	i += half + 1;
-	count -= half + 1;
-      } else
-	count = half;
-    }
+    unsigned int pos;
+    auto cmp = +[](const void* key, const void* p,
+                   int sign, hb_font_t* font, const MathKern* mathKern) -> int {
+      return sign * *(hb_position_t*)key - sign * ((MathValueRecord*)p)->get_y_value(font, mathKern);
+    };
+    unsigned int i = hb_bsearch_impl(&pos, correction_height, correctionHeight,
+                                     heightCount, MathValueRecord::static_size,
+                                     cmp, sign, font, this) ? pos + 1 : pos;
     return kernValue[i].get_x_value (font, this);
   }
 
@@ -984,6 +978,7 @@
     return_trace (c->check_struct (this) &&
 		  vertGlyphCoverage.sanitize (c, this) &&
 		  horizGlyphCoverage.sanitize (c, this) &&
+		  hb_barrier () &&
 		  c->check_array (glyphConstruction.arrayZ, vertGlyphCount + horizGlyphCount) &&
 		  sanitize_offsets (c));
   }
@@ -1103,6 +1098,7 @@
     TRACE_SANITIZE (this);
     return_trace (version.sanitize (c) &&
 		  likely (version.major == 1) &&
+		  hb_barrier () &&
 		  mathConstants.sanitize (c, this) &&
 		  mathGlyphInfo.sanitize (c, this) &&
 		  mathVariants.sanitize (c, this));
diff --git a/src/hb-ot-maxp-table.hh b/src/hb-ot-maxp-table.hh
index 0f4cc41..8f00052 100644
--- a/src/hb-ot-maxp-table.hh
+++ b/src/hb-ot-maxp-table.hh
@@ -85,7 +85,7 @@
     TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this)))
       return_trace (false);
-
+    hb_barrier ();
     if (version.major == 1)
     {
       const maxpV1Tail &v1 = StructAfter<maxpV1Tail> (*this);
@@ -103,6 +103,7 @@
     maxp_prime->numGlyphs = hb_min (c->plan->num_output_glyphs (), 0xFFFFu);
     if (maxp_prime->version.major == 1)
     {
+      hb_barrier ();
       const maxpV1Tail *src_v1 = &StructAfter<maxpV1Tail> (*this);
       maxpV1Tail *dest_v1 = c->serializer->embed<maxpV1Tail> (src_v1);
       if (unlikely (!dest_v1)) return_trace (false);
diff --git a/src/hb-ot-meta-table.hh b/src/hb-ot-meta-table.hh
index e1b68bc..658db58 100644
--- a/src/hb-ot-meta-table.hh
+++ b/src/hb-ot-meta-table.hh
@@ -51,6 +51,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (likely (c->check_struct (this) &&
+			  hb_barrier () &&
 			  dataZ.sanitize (c, base, dataLength)));
   }
 
@@ -101,6 +102,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (likely (c->check_struct (this) &&
+			  hb_barrier () &&
 			  version == 1 &&
 			  dataMaps.sanitize (c, this)));
   }
diff --git a/src/hb-ot-os2-table.hh b/src/hb-ot-os2-table.hh
index 19330b9..6c91402 100644
--- a/src/hb-ot-os2-table.hh
+++ b/src/hb-ot-os2-table.hh
@@ -209,6 +209,23 @@
     return ret;
   }
 
+  static unsigned calc_avg_char_width (const hb_hashmap_t<hb_codepoint_t, hb_pair_t<unsigned, int>>& hmtx_map)
+  {
+    unsigned num = 0;
+    unsigned total_width = 0;
+    for (const auto& _ : hmtx_map.values_ref ())
+    {
+      unsigned width = _.first;
+      if (width)
+      {
+        total_width += width;
+        num++;
+      }
+    }
+
+    return num ? (unsigned) roundf ((double) total_width / (double) num) : 0;
+  }
+
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
@@ -239,17 +256,23 @@
 
       if (os2_prime->version >= 2)
       {
+        hb_barrier ();
         auto *table = & const_cast<OS2V2Tail &> (os2_prime->v2 ());
         HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_X_HEIGHT,                   sxHeight);
         HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_CAP_HEIGHT,                 sCapHeight);
       }
+
+      unsigned avg_char_width = calc_avg_char_width (c->plan->hmtx_map);
+      if (!c->serializer->check_assign (os2_prime->xAvgCharWidth, avg_char_width,
+                                        HB_SERIALIZE_ERROR_INT_OVERFLOW))
+        return_trace (false);
     }
 #endif
 
     Triple *axis_range;
     if (c->plan->user_axes_location.has (HB_TAG ('w','g','h','t'), &axis_range))
     {
-      unsigned weight_class = static_cast<unsigned> (roundf (hb_clamp (axis_range->middle, 1.0f, 1000.0f)));
+      unsigned weight_class = static_cast<unsigned> (roundf (hb_clamp (axis_range->middle, 1.0, 1000.0)));
       if (os2_prime->usWeightClass != weight_class)
         os2_prime->usWeightClass = weight_class;
     }
@@ -261,12 +284,12 @@
         os2_prime->usWidthClass = width_class;
     }
 
-    if (c->plan->flags & HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES)
-      return_trace (true);
-
     os2_prime->usFirstCharIndex = hb_min (0xFFFFu, c->plan->unicodes.get_min ());
     os2_prime->usLastCharIndex  = hb_min (0xFFFFu, c->plan->unicodes.get_max ());
 
+    if (c->plan->flags & HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES)
+      return_trace (true);
+
     _update_unicode_ranges (&c->plan->unicodes, os2_prime->ulUnicodeRange);
 
     return_trace (true);
@@ -334,6 +357,7 @@
   {
     TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this))) return_trace (false);
+    hb_barrier ();
     if (unlikely (version >= 1 && !v1X.sanitize (c))) return_trace (false);
     if (unlikely (version >= 2 && !v2X.sanitize (c))) return_trace (false);
     if (unlikely (version >= 5 && !v5X.sanitize (c))) return_trace (false);
diff --git a/src/hb-ot-post-table.hh b/src/hb-ot-post-table.hh
index aaecc34..4191879 100644
--- a/src/hb-ot-post-table.hh
+++ b/src/hb-ot-post-table.hh
@@ -116,13 +116,16 @@
     Triple *axis_range;
     if (c->plan->user_axes_location.has (HB_TAG ('s','l','n','t'), &axis_range))
     {
-      float italic_angle = hb_max (-90.f, hb_min (axis_range->middle, 90.f));
+      float italic_angle = hb_max (-90.0, hb_min (axis_range->middle, 90.0));
       if (post_prime->italicAngle.to_float () != italic_angle)
         post_prime->italicAngle.set_float (italic_angle);
     }
 
     if (glyph_names && version.major == 2)
+    {
+      hb_barrier ();
       return_trace (v2X.subset (c));
+    }
 
     return_trace (true);
   }
@@ -138,6 +141,7 @@
 
       version = table->version.to_int ();
       if (version != 0x00020000) return;
+      hb_barrier ();
 
       const postV2Tail &v2 = table->v2X;
 
@@ -217,10 +221,16 @@
     unsigned int get_glyph_count () const
     {
       if (version == 0x00010000)
+      {
+        hb_barrier ();
 	return format1_names_length;
+      }
 
       if (version == 0x00020000)
+      {
+        hb_barrier ();
 	return glyphNameIndex->len;
+      }
 
       return 0;
     }
@@ -245,13 +255,18 @@
     {
       if (version == 0x00010000)
       {
+        hb_barrier ();
 	if (glyph >= format1_names_length)
 	  return hb_bytes_t ();
 
 	return format1_names (glyph);
       }
 
-      if (version != 0x00020000 || glyph >= glyphNameIndex->len)
+      if (version != 0x00020000)
+	return hb_bytes_t ();
+      hb_barrier ();
+
+      if (glyph >= glyphNameIndex->len)
 	return hb_bytes_t ();
 
       unsigned int index = glyphNameIndex->arrayZ[glyph];
@@ -284,6 +299,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
+		  hb_barrier () &&
 		  (version.to_int () == 0x00010000 ||
 		   (version.to_int () == 0x00020000 && v2X.sanitize (c)) ||
 		   version.to_int () == 0x00030000));
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 90f596a..1488300 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -155,7 +155,7 @@
 #endif
   bool has_gpos = !disable_gpos && hb_ot_layout_has_positioning (face);
   if (false)
-    ;
+    {}
 #ifndef HB_NO_AAT_SHAPE
   /* Prefer GPOS over kerx if GSUB is present;
    * https://github.com/harfbuzz/harfbuzz/issues/3008 */
@@ -167,15 +167,16 @@
 
   if (!plan.apply_kerx && (!has_gpos_kern || !plan.apply_gpos))
   {
+    if (false) {}
 #ifndef HB_NO_AAT_SHAPE
-    if (has_kerx)
+    else if (has_kerx)
       plan.apply_kerx = true;
-    else
 #endif
 #ifndef HB_NO_OT_KERN
-    if (hb_ot_layout_has_kerning (face))
+    else if (hb_ot_layout_has_kerning (face))
       plan.apply_kern = true;
 #endif
+    else {}
   }
 
   plan.apply_fallback_kern = !(plan.apply_gpos || plan.apply_kerx || plan.apply_kern);
diff --git a/src/hb-ot-shaper-arabic.cc b/src/hb-ot-shaper-arabic.cc
index 70a1dff..8aa2b8f 100644
--- a/src/hb-ot-shaper-arabic.cc
+++ b/src/hb-ot-shaper-arabic.cc
@@ -560,9 +560,9 @@
 
       DEBUG_MSG (ARABIC, nullptr, "%s stretch at (%u,%u,%u)",
 		 step == MEASURE ? "measuring" : "cutting", context, start, end);
-      DEBUG_MSG (ARABIC, nullptr, "rest of word:    count=%u width %" PRId32 "", start - context, w_total);
-      DEBUG_MSG (ARABIC, nullptr, "fixed tiles:     count=%d width=%" PRId32 "", n_fixed, w_fixed);
-      DEBUG_MSG (ARABIC, nullptr, "repeating tiles: count=%d width=%" PRId32 "", n_repeating, w_repeating);
+      DEBUG_MSG (ARABIC, nullptr, "rest of word:    count=%u width %" PRId32, start - context, w_total);
+      DEBUG_MSG (ARABIC, nullptr, "fixed tiles:     count=%d width=%" PRId32, n_fixed, w_fixed);
+      DEBUG_MSG (ARABIC, nullptr, "repeating tiles: count=%d width=%" PRId32, n_repeating, w_repeating);
 
       /* Number of additional times to repeat each repeating tile. */
       int n_copies = 0;
diff --git a/src/hb-ot-stat-table.hh b/src/hb-ot-stat-table.hh
index f7bb379..ea5459e 100644
--- a/src/hb-ot-stat-table.hh
+++ b/src/hb-ot-stat-table.hh
@@ -63,8 +63,9 @@
   if (!user_axes_location->has (axis_tag))
     return false;
 
+  double axis_value_double = static_cast<double>(axis_value);
   Triple axis_range = user_axes_location->get (axis_tag);
-  return (axis_value < axis_range.minimum || axis_value > axis_range.maximum);
+  return (axis_value_double < axis_range.minimum || axis_value_double > axis_range.maximum);
 }
 
 struct StatAxisRecord
@@ -327,6 +328,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (likely (c->check_struct (this) &&
+			  hb_barrier () &&
                           axisValues.sanitize (c, axisCount)));
   }
 
@@ -348,7 +350,7 @@
 
 struct AxisValue
 {
-  bool get_value (unsigned int axis_index) const
+  float get_value (unsigned int axis_index) const
   {
     switch (u.format)
     {
@@ -356,7 +358,7 @@
     case 2: return u.format2.get_value ();
     case 3: return u.format3.get_value ();
     case 4: return u.format4.get_axis_record (axis_index).get_value ();
-    default:return 0;
+    default:return 0.f;
     }
   }
 
@@ -416,6 +418,7 @@
     TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this)))
       return_trace (false);
+    hb_barrier ();
 
     switch (u.format)
     {
@@ -483,7 +486,7 @@
     hb_array_t<const Offset16To<AxisValue>> axis_values = get_axis_value_offsets ();
     for (unsigned int i = 0; i < axis_values.length; i++)
     {
-      const AxisValue& axis_value = this+axis_values[i];
+      const AxisValue& axis_value = this+offsetToAxisValueOffsets+axis_values[i];
       if (axis_value.get_axis_index () == axis_index)
       {
 	if (value)
@@ -560,6 +563,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (likely (c->check_struct (this) &&
+			  hb_barrier () &&
 			  version.major == 1 &&
 			  version.minor > 0 &&
 			  designAxesOffset.sanitize (c, this, designAxisCount) &&
diff --git a/src/hb-ot-tag-table.hh b/src/hb-ot-tag-table.hh
index 032a7c8..920b06b 100644
--- a/src/hb-ot-tag-table.hh
+++ b/src/hb-ot-tag-table.hh
@@ -6,8 +6,8 @@
  *
  * on files with these headers:
  *
- * <meta name="updated_at" content="2022-09-30 11:47 PM" />
- * File-Date: 2023-08-02
+ * <meta name="updated_at" content="2023-09-30 01:21 AM" />
+ * File-Date: 2024-03-07
  */
 
 #ifndef HB_OT_TAG_TABLE_HH
@@ -31,7 +31,7 @@
   {HB_TAG('b','i',' ',' '),	HB_TAG('B','I','S',' ')},	/* Bislama */
   {HB_TAG('b','i',' ',' '),	HB_TAG('C','P','P',' ')},	/* Bislama -> Creoles */
   {HB_TAG('b','m',' ',' '),	HB_TAG('B','M','B',' ')},	/* Bambara (Bamanankan) */
-  {HB_TAG('b','n',' ',' '),	HB_TAG('B','E','N',' ')},	/* Bengali */
+  {HB_TAG('b','n',' ',' '),	HB_TAG('B','E','N',' ')},	/* Bangla */
   {HB_TAG('b','o',' ',' '),	HB_TAG('T','I','B',' ')},	/* Tibetan */
   {HB_TAG('b','r',' ',' '),	HB_TAG('B','R','E',' ')},	/* Breton */
   {HB_TAG('b','s',' ',' '),	HB_TAG('B','O','S',' ')},	/* Bosnian */
@@ -64,7 +64,7 @@
   {HB_TAG('f','r',' ',' '),	HB_TAG('F','R','A',' ')},	/* French */
   {HB_TAG('f','y',' ',' '),	HB_TAG('F','R','I',' ')},	/* Western Frisian -> Frisian */
   {HB_TAG('g','a',' ',' '),	HB_TAG('I','R','I',' ')},	/* Irish */
-  {HB_TAG('g','d',' ',' '),	HB_TAG('G','A','E',' ')},	/* Scottish Gaelic (Gaelic) */
+  {HB_TAG('g','d',' ',' '),	HB_TAG('G','A','E',' ')},	/* Scottish Gaelic */
   {HB_TAG('g','l',' ',' '),	HB_TAG('G','A','L',' ')},	/* Galician */
   {HB_TAG('g','n',' ',' '),	HB_TAG('G','U','A',' ')},	/* Guarani [macrolanguage] */
   {HB_TAG('g','u',' ',' '),	HB_TAG('G','U','J',' ')},	/* Gujarati */
@@ -132,7 +132,7 @@
   {HB_TAG('m','l',' ',' '),	HB_TAG('M','A','L',' ')},	/* Malayalam -> Malayalam Traditional */
   {HB_TAG('m','l',' ',' '),	HB_TAG('M','L','R',' ')},	/* Malayalam -> Malayalam Reformed */
   {HB_TAG('m','n',' ',' '),	HB_TAG('M','N','G',' ')},	/* Mongolian [macrolanguage] */
-  {HB_TAG('m','o',' ',' '),	HB_TAG('M','O','L',' ')},	/* Moldavian (retired code) */
+  {HB_TAG('m','o',' ',' '),	HB_TAG('M','O','L',' ')},	/* Moldavian (retired code) -> Romanian (Moldova) */
   {HB_TAG('m','o',' ',' '),	HB_TAG('R','O','M',' ')},	/* Moldavian (retired code) -> Romanian */
   {HB_TAG('m','r',' ',' '),	HB_TAG('M','A','R',' ')},	/* Marathi */
   {HB_TAG('m','s',' ',' '),	HB_TAG('M','L','Y',' ')},	/* Malay [macrolanguage] */
@@ -153,7 +153,7 @@
   {HB_TAG('o','c',' ',' '),	HB_TAG('O','C','I',' ')},	/* Occitan (post 1500) */
   {HB_TAG('o','j',' ',' '),	HB_TAG('O','J','B',' ')},	/* Ojibwa [macrolanguage] -> Ojibway */
   {HB_TAG('o','m',' ',' '),	HB_TAG('O','R','O',' ')},	/* Oromo [macrolanguage] */
-  {HB_TAG('o','r',' ',' '),	HB_TAG('O','R','I',' ')},	/* Odia (formerly Oriya) [macrolanguage] */
+  {HB_TAG('o','r',' ',' '),	HB_TAG('O','R','I',' ')},	/* Odia [macrolanguage] */
   {HB_TAG('o','s',' ',' '),	HB_TAG('O','S','S',' ')},	/* Ossetian */
   {HB_TAG('p','a',' ',' '),	HB_TAG('P','A','N',' ')},	/* Punjabi */
   {HB_TAG('p','i',' ',' '),	HB_TAG('P','A','L',' ')},	/* Pali */
@@ -166,7 +166,7 @@
   {HB_TAG('r','o',' ',' '),	HB_TAG('R','O','M',' ')},	/* Romanian */
   {HB_TAG('r','u',' ',' '),	HB_TAG('R','U','S',' ')},	/* Russian */
   {HB_TAG('r','w',' ',' '),	HB_TAG('R','U','A',' ')},	/* Kinyarwanda */
-  {HB_TAG('s','a',' ',' '),	HB_TAG('S','A','N',' ')},	/* Sanskrit */
+  {HB_TAG('s','a',' ',' '),	HB_TAG('S','A','N',' ')},	/* Sanskrit [macrolanguage] */
   {HB_TAG('s','c',' ',' '),	HB_TAG('S','R','D',' ')},	/* Sardinian [macrolanguage] */
   {HB_TAG('s','d',' ',' '),	HB_TAG('S','N','D',' ')},	/* Sindhi */
   {HB_TAG('s','e',' ',' '),	HB_TAG('N','S','M',' ')},	/* Northern Sami */
@@ -465,6 +465,7 @@
   {HB_TAG('c','l','d',' '),	HB_TAG('S','Y','R',' ')},	/* Chaldean Neo-Aramaic -> Syriac */
   {HB_TAG('c','l','e',' '),	HB_TAG('C','C','H','N')},	/* Lealao Chinantec -> Chinantec */
   {HB_TAG('c','l','j',' '),	HB_TAG('Q','I','N',' ')},	/* Laitu Chin -> Chin */
+  {HB_TAG('c','l','s',' '),	HB_TAG('S','A','N',' ')},	/* Classical Sanskrit -> Sanskrit */
   {HB_TAG('c','l','t',' '),	HB_TAG('Q','I','N',' ')},	/* Lautu Chin -> Chin */
   {HB_TAG('c','m','n',' '),	HB_TAG('Z','H','S',' ')},	/* Mandarin Chinese -> Chinese, Simplified */
   {HB_TAG('c','m','r',' '),	HB_TAG('Q','I','N',' ')},	/* Mro-Khimi Chin -> Chin */
@@ -637,7 +638,7 @@
   {HB_TAG('g','a','a',' '),	HB_TAG('G','A','D',' ')},	/* Ga */
   {HB_TAG('g','a','c',' '),	HB_TAG('C','P','P',' ')},	/* Mixed Great Andamanese -> Creoles */
   {HB_TAG('g','a','d',' '),	HB_TAG_NONE	       },	/* Gaddang != Ga */
-  {HB_TAG('g','a','e',' '),	HB_TAG_NONE	       },	/* Guarequena != Scottish Gaelic (Gaelic) */
+  {HB_TAG('g','a','e',' '),	HB_TAG_NONE	       },	/* Guarequena != Scottish Gaelic */
 /*{HB_TAG('g','a','g',' '),	HB_TAG('G','A','G',' ')},*/	/* Gagauz */
   {HB_TAG('g','a','l',' '),	HB_TAG_NONE	       },	/* Galolen != Galician */
   {HB_TAG('g','a','n',' '),	HB_TAG('Z','H','S',' ')},	/* Gan Chinese -> Chinese, Simplified */
@@ -1160,7 +1161,7 @@
   {HB_TAG('o','r','o',' '),	HB_TAG_NONE	       },	/* Orokolo != Oromo */
   {HB_TAG('o','r','r',' '),	HB_TAG('I','J','O',' ')},	/* Oruma -> Ijo */
   {HB_TAG('o','r','s',' '),	HB_TAG('M','L','Y',' ')},	/* Orang Seletar -> Malay */
-  {HB_TAG('o','r','y',' '),	HB_TAG('O','R','I',' ')},	/* Odia (formerly Oriya) */
+  {HB_TAG('o','r','y',' '),	HB_TAG('O','R','I',' ')},	/* Odia */
   {HB_TAG('o','t','w',' '),	HB_TAG('O','J','B',' ')},	/* Ottawa -> Ojibway */
   {HB_TAG('o','u','a',' '),	HB_TAG('B','B','R',' ')},	/* Tagargrent -> Berber */
   {HB_TAG('p','a','a',' '),	HB_TAG_NONE	       },	/* Papuan [collection] != Palestinian Aramaic */
@@ -1395,7 +1396,7 @@
 /*{HB_TAG('s','n','k',' '),	HB_TAG('S','N','K',' ')},*/	/* Soninke */
   {HB_TAG('s','o','g',' '),	HB_TAG_NONE	       },	/* Sogdian != Sodo Gurage */
 /*{HB_TAG('s','o','p',' '),	HB_TAG('S','O','P',' ')},*/	/* Songe */
-  {HB_TAG('s','p','v',' '),	HB_TAG('O','R','I',' ')},	/* Sambalpuri -> Odia (formerly Oriya) */
+  {HB_TAG('s','p','v',' '),	HB_TAG('O','R','I',' ')},	/* Sambalpuri -> Odia */
   {HB_TAG('s','p','y',' '),	HB_TAG('K','A','L',' ')},	/* Sabaot -> Kalenjin */
   {HB_TAG('s','r','b',' '),	HB_TAG_NONE	       },	/* Sora != Serbian */
   {HB_TAG('s','r','c',' '),	HB_TAG('S','R','D',' ')},	/* Logudorese Sardinian -> Sardinian */
@@ -1533,6 +1534,7 @@
   {HB_TAG('v','l','s',' '),	HB_TAG('F','L','E',' ')},	/* Vlaams -> Dutch (Flemish) */
   {HB_TAG('v','m','w',' '),	HB_TAG('M','A','K',' ')},	/* Makhuwa */
 /*{HB_TAG('v','r','o',' '),	HB_TAG('V','R','O',' ')},*/	/* Võro */
+  {HB_TAG('v','s','n',' '),	HB_TAG('S','A','N',' ')},	/* Vedic Sanskrit -> Sanskrit */
   {HB_TAG('w','a','g',' '),	HB_TAG_NONE	       },	/* Wa'ema != Wagdi */
 /*{HB_TAG('w','a','r',' '),	HB_TAG('W','A','R',' ')},*/	/* Waray (Philippines) -> Waray-Waray */
   {HB_TAG('w','b','m',' '),	HB_TAG('W','A',' ',' ')},	/* Wa */
@@ -2643,7 +2645,7 @@
       /* Romanian; Moldova */
       unsigned int i;
       hb_tag_t possible_tags[] = {
-	HB_TAG('M','O','L',' '),  /* Moldavian */
+	HB_TAG('M','O','L',' '),  /* Romanian (Moldova) */
 	HB_TAG('R','O','M',' '),  /* Romanian */
       };
       for (i = 0; i < 2 && i < *count; i++)
@@ -2816,9 +2818,10 @@
  * @tag: A language tag.
  *
  * Converts @tag to a BCP 47 language tag if it is ambiguous (it corresponds to
- * many language tags) and the best tag is not the alphabetically first, or if
- * the best tag consists of multiple subtags, or if the best tag does not appear
- * in #ot_languages.
+ * many language tags) and the best tag is not the first (sorted alphabetically,
+ * with two-letter tags having priority over all three-letter tags), or if the
+ * best tag consists of multiple subtags, or if the best tag does not appear in
+ * #ot_languages2 or #ot_languages3.
  *
  * Return value: The #hb_language_t corresponding to the BCP 47 language tag,
  * or #HB_LANGUAGE_INVALID if @tag is not ambiguous.
@@ -2832,8 +2835,6 @@
     return hb_language_from_string ("alt", -1);  /* Southern Altai */
   case HB_TAG('A','P','P','H'):  /* Phonetic transcription—Americanist conventions */
     return hb_language_from_string ("und-fonnapa", -1);  /* Undetermined; North American Phonetic Alphabet */
-  case HB_TAG('A','R','A',' '):  /* Arabic */
-    return hb_language_from_string ("ar", -1);  /* Arabic [macrolanguage] */
   case HB_TAG('A','R','K',' '):  /* Rakhine */
     return hb_language_from_string ("rki", -1);  /* Rakhine */
   case HB_TAG('A','T','H',' '):  /* Athapaskan */
@@ -2854,12 +2855,6 @@
     return hb_language_from_string ("din", -1);  /* Dinka [macrolanguage] */
   case HB_TAG('D','R','I',' '):  /* Dari */
     return hb_language_from_string ("prs", -1);  /* Dari */
-  case HB_TAG('D','Z','N',' '):  /* Dzongkha */
-    return hb_language_from_string ("dz", -1);  /* Dzongkha */
-  case HB_TAG('E','T','I',' '):  /* Estonian */
-    return hb_language_from_string ("et", -1);  /* Estonian [macrolanguage] */
-  case HB_TAG('F','A','R',' '):  /* Persian */
-    return hb_language_from_string ("fa", -1);  /* Persian [macrolanguage] */
   case HB_TAG('G','O','N',' '):  /* Gondi */
     return hb_language_from_string ("gon", -1);  /* Gondi [macrolanguage] */
   case HB_TAG('H','M','A',' '):  /* High Mari */
@@ -2874,10 +2869,6 @@
     return hb_language_from_string ("iba", -1);  /* Iban */
   case HB_TAG('I','J','O',' '):  /* Ijo */
     return hb_language_from_string ("ijo", -1);  /* Ijo [collection] */
-  case HB_TAG('I','N','U',' '):  /* Inuktitut */
-    return hb_language_from_string ("iu", -1);  /* Inuktitut [macrolanguage] */
-  case HB_TAG('I','P','K',' '):  /* Inupiat */
-    return hb_language_from_string ("ik", -1);  /* Inupiaq [macrolanguage] */
   case HB_TAG('I','P','P','H'):  /* Phonetic transcription—IPA conventions */
     return hb_language_from_string ("und-fonipa", -1);  /* Undetermined; International Phonetic Alphabet */
   case HB_TAG('I','R','T',' '):  /* Irish Traditional */
@@ -2888,39 +2879,27 @@
     return hb_language_from_string ("kln", -1);  /* Kalenjin [macrolanguage] */
   case HB_TAG('K','G','E',' '):  /* Khutsuri Georgian */
     return hb_language_from_string ("und-Geok", -1);  /* Undetermined; Khutsuri (Asomtavruli and Nuskhuri) */
-  case HB_TAG('K','N','R',' '):  /* Kanuri */
-    return hb_language_from_string ("kr", -1);  /* Kanuri [macrolanguage] */
   case HB_TAG('K','O','H',' '):  /* Korean Old Hangul */
     return hb_language_from_string ("okm", -1);  /* Middle Korean (10th-16th cent.) */
   case HB_TAG('K','O','K',' '):  /* Konkani */
     return hb_language_from_string ("kok", -1);  /* Konkani [macrolanguage] */
-  case HB_TAG('K','O','M',' '):  /* Komi */
-    return hb_language_from_string ("kv", -1);  /* Komi [macrolanguage] */
   case HB_TAG('K','P','L',' '):  /* Kpelle */
     return hb_language_from_string ("kpe", -1);  /* Kpelle [macrolanguage] */
   case HB_TAG('K','R','N',' '):  /* Karen */
     return hb_language_from_string ("kar", -1);  /* Karen [collection] */
   case HB_TAG('K','U','I',' '):  /* Kui */
     return hb_language_from_string ("uki", -1);  /* Kui (India) */
-  case HB_TAG('K','U','R',' '):  /* Kurdish */
-    return hb_language_from_string ("ku", -1);  /* Kurdish [macrolanguage] */
   case HB_TAG('L','M','A',' '):  /* Low Mari */
     return hb_language_from_string ("mhr", -1);  /* Eastern Mari */
   case HB_TAG('L','U','H',' '):  /* Luyia */
     return hb_language_from_string ("luy", -1);  /* Luyia [macrolanguage] */
-  case HB_TAG('L','V','I',' '):  /* Latvian */
-    return hb_language_from_string ("lv", -1);  /* Latvian [macrolanguage] */
   case HB_TAG('M','A','W',' '):  /* Marwari */
     return hb_language_from_string ("mwr", -1);  /* Marwari [macrolanguage] */
-  case HB_TAG('M','L','G',' '):  /* Malagasy */
-    return hb_language_from_string ("mg", -1);  /* Malagasy [macrolanguage] */
   case HB_TAG('M','L','Y',' '):  /* Malay */
     return hb_language_from_string ("ms", -1);  /* Malay [macrolanguage] */
-  case HB_TAG('M','N','G',' '):  /* Mongolian */
-    return hb_language_from_string ("mn", -1);  /* Mongolian [macrolanguage] */
   case HB_TAG('M','N','K',' '):  /* Maninka */
     return hb_language_from_string ("man", -1);  /* Mandingo [macrolanguage] */
-  case HB_TAG('M','O','L',' '):  /* Moldavian */
+  case HB_TAG('M','O','L',' '):  /* Romanian (Moldova) */
     return hb_language_from_string ("ro-MD", -1);  /* Romanian; Moldova */
   case HB_TAG('M','O','N','T'):  /* Thailand Mon */
     return hb_language_from_string ("mnw-TH", -1);  /* Mon; Thailand */
@@ -2928,26 +2907,16 @@
     return hb_language_from_string ("myn", -1);  /* Mayan [collection] */
   case HB_TAG('N','A','H',' '):  /* Nahuatl */
     return hb_language_from_string ("nah", -1);  /* Nahuatl [collection] */
-  case HB_TAG('N','E','P',' '):  /* Nepali */
-    return hb_language_from_string ("ne", -1);  /* Nepali [macrolanguage] */
   case HB_TAG('N','I','S',' '):  /* Nisi */
     return hb_language_from_string ("njz", -1);  /* Nyishi */
   case HB_TAG('N','O','R',' '):  /* Norwegian */
     return hb_language_from_string ("no", -1);  /* Norwegian [macrolanguage] */
-  case HB_TAG('O','J','B',' '):  /* Ojibway */
-    return hb_language_from_string ("oj", -1);  /* Ojibwa [macrolanguage] */
-  case HB_TAG('O','R','O',' '):  /* Oromo */
-    return hb_language_from_string ("om", -1);  /* Oromo [macrolanguage] */
-  case HB_TAG('P','A','S',' '):  /* Pashto */
-    return hb_language_from_string ("ps", -1);  /* Pashto [macrolanguage] */
   case HB_TAG('P','G','R',' '):  /* Polytonic Greek */
     return hb_language_from_string ("el-polyton", -1);  /* Modern Greek (1453-); Polytonic Greek */
   case HB_TAG('P','R','O',' '):  /* Provençal / Old Provençal */
     return hb_language_from_string ("pro", -1);  /* Old Provençal (to 1500) */
   case HB_TAG('Q','U','H',' '):  /* Quechua (Bolivia) */
     return hb_language_from_string ("quh", -1);  /* South Bolivian Quechua */
-  case HB_TAG('Q','U','Z',' '):  /* Quechua */
-    return hb_language_from_string ("qu", -1);  /* Quechua [macrolanguage] */
   case HB_TAG('Q','V','I',' '):  /* Quechua (Ecuador) */
     return hb_language_from_string ("qvi", -1);  /* Imbabura Highland Quichua */
   case HB_TAG('Q','W','H',' '):  /* Quechua (Peru) */
@@ -2958,8 +2927,6 @@
     return hb_language_from_string ("ro", -1);  /* Romanian */
   case HB_TAG('R','O','Y',' '):  /* Romany */
     return hb_language_from_string ("rom", -1);  /* Romany [macrolanguage] */
-  case HB_TAG('S','Q','I',' '):  /* Albanian */
-    return hb_language_from_string ("sq", -1);  /* Albanian [macrolanguage] */
   case HB_TAG('S','R','B',' '):  /* Serbian */
     return hb_language_from_string ("sr", -1);  /* Serbian */
   case HB_TAG('S','X','T',' '):  /* Sutu */
diff --git a/src/hb-ot-tag.cc b/src/hb-ot-tag.cc
index d8b1151..4cb6f6c 100644
--- a/src/hb-ot-tag.cc
+++ b/src/hb-ot-tag.cc
@@ -548,7 +548,7 @@
       buf[3] = '-';
       str += 4;
     }
-    snprintf (str, 16, "x-hbot-%08" PRIx32 "", tag);
+    snprintf (str, 16, "x-hbot-%08" PRIx32, tag);
     return hb_language_from_string (&*buf, -1);
   }
 }
diff --git a/src/hb-ot-var-avar-table.hh b/src/hb-ot-var-avar-table.hh
index f3754aa..75ea338 100644
--- a/src/hb-ot-var-avar-table.hh
+++ b/src/hb-ot-var-avar-table.hh
@@ -57,7 +57,7 @@
 
   protected:
   Offset32To<DeltaSetIndexMap>	varIdxMap;	/* Offset from the beginning of 'avar' table. */
-  Offset32To<VariationStore>	varStore;	/* Offset from the beginning of 'avar' table. */
+  Offset32To<ItemVariationStore>	varStore;	/* Offset from the beginning of 'avar' table. */
 
   public:
   DEFINE_SIZE_STATIC (8);
@@ -80,7 +80,7 @@
 
   bool is_outside_axis_range (const Triple& axis_range) const
   {
-    float from_coord = coords[0].to_float ();
+    double from_coord = (double) coords[0].to_float ();
     return !axis_range.contains (from_coord);
   }
 
@@ -100,8 +100,8 @@
     float from_coord = coords[0].to_float ();
     float to_coord = coords[1].to_float ();
 
-    from_coord = renormalizeValue (from_coord, unmapped_range, triple_distances);
-    to_coord = renormalizeValue (to_coord, axis_range, triple_distances);
+    from_coord = renormalizeValue ((double) from_coord, unmapped_range, triple_distances);
+    to_coord = renormalizeValue ((double) to_coord, axis_range, triple_distances);
 
     coords[0].set_float (from_coord);
     coords[1].set_float (to_coord);
@@ -197,7 +197,7 @@
     unmapped_val.set_int (unmap (val.to_int ()));
     float unmapped_max = unmapped_val.to_float ();
 
-    return Triple{unmapped_min, unmapped_middle, unmapped_max};
+    return Triple{(double) unmapped_min, (double) unmapped_middle, (double) unmapped_max};
   }
 
   bool subset (hb_subset_context_t *c, hb_tag_t axis_tag) const
@@ -230,7 +230,7 @@
        * duplicates here */
       if (mapping.must_include ())
         continue;
-      value_mappings.push (std::move (mapping));
+      value_mappings.push (mapping);
     }
 
     AxisValueMap m;
@@ -273,6 +273,7 @@
   {
     TRACE_SANITIZE (this);
     if (!(version.sanitize (c) &&
+	  hb_barrier () &&
 	  (version.major == 1
 #ifndef HB_NO_AVAR2
 	   || version.major == 2
@@ -293,6 +294,7 @@
 #ifndef HB_NO_AVAR2
     if (version.major < 2)
       return_trace (true);
+    hb_barrier ();
 
     const auto &v2 = * (const avarV2Tail *) map;
     if (unlikely (!v2.sanitize (c, this)))
@@ -316,6 +318,7 @@
 #ifndef HB_NO_AVAR2
     if (version.major < 2)
       return;
+    hb_barrier ();
 
     for (; count < axisCount; count++)
       map = &StructAfter<SegmentMaps> (*map);
@@ -340,7 +343,7 @@
     for (unsigned i = 0; i < coords_length; i++)
       coords[i] = out[i];
 
-    OT::VariationStore::destroy_cache (var_store_cache);
+    OT::ItemVariationStore::destroy_cache (var_store_cache);
 #endif
   }
 
diff --git a/src/hb-ot-var-common.hh b/src/hb-ot-var-common.hh
index b6fe13f..08227aa 100644
--- a/src/hb-ot-var-common.hh
+++ b/src/hb-ot-var-common.hh
@@ -28,6 +28,7 @@
 
 #include "hb-ot-layout-common.hh"
 #include "hb-priority-queue.hh"
+#include "hb-subset-instancer-iup.hh"
 
 
 namespace OT {
@@ -119,6 +120,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
+		  hb_barrier () &&
                   c->check_range (mapDataZ.arrayZ,
                                   mapCount,
                                   get_width ()));
@@ -191,6 +193,7 @@
   {
     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 1: return_trace (u.format1.sanitize (c));
@@ -219,9 +222,9 @@
 };
 
 
-struct VarStoreInstancer
+struct ItemVarStoreInstancer
 {
-  VarStoreInstancer (const VariationStore *varStore,
+  ItemVarStoreInstancer (const ItemVariationStore *varStore,
 		     const DeltaSetIndexMap *varIdxMap,
 		     hb_array_t<int> coords) :
     varStore (varStore), varIdxMap (varIdxMap), coords (coords) {}
@@ -233,7 +236,7 @@
   float operator() (uint32_t varIdx, unsigned short offset = 0) const
   { return coords ? varStore->get_delta (varIdxMap ? varIdxMap->map (VarIdx::add (varIdx, offset)) : varIdx + offset, coords) : 0; }
 
-  const VariationStore *varStore;
+  const ItemVariationStore *varStore;
   const DeltaSetIndexMap *varIdxMap;
   hb_array_t<int> coords;
 };
@@ -296,13 +299,13 @@
         start = hb_min (peak, 0.f);
         end = hb_max (peak, 0.f);
       }
-      axis_tuples.set (*axis_tag, Triple (start, peak, end));
+      axis_tuples.set (*axis_tag, Triple ((double) start, (double) peak, (double) end));
     }
 
     return true;
   }
 
-  float calculate_scalar (hb_array_t<int> coords, unsigned int coord_count,
+  double calculate_scalar (hb_array_t<int> coords, unsigned int coord_count,
                           const hb_array_t<const F2DOT14> shared_tuples,
 			  const hb_vector_t<hb_pair_t<int,int>> *shared_tuple_active_idx = nullptr) const
   {
@@ -318,13 +321,13 @@
     {
       unsigned int index = get_index ();
       if (unlikely ((index + 1) * coord_count > shared_tuples.length))
-        return 0.f;
+        return 0.0;
       peak_tuple = shared_tuples.sub_array (coord_count * index, coord_count).arrayZ;
 
       if (shared_tuple_active_idx)
       {
 	if (unlikely (index >= shared_tuple_active_idx->length))
-	  return 0.f;
+	  return 0.0;
 	auto _ = (*shared_tuple_active_idx).arrayZ[index];
 	if (_.second != -1)
 	{
@@ -349,7 +352,7 @@
       end_tuple = get_end_tuple (coord_count).arrayZ;
     }
 
-    float scalar = 1.f;
+    double scalar = 1.0;
     for (unsigned int i = start_idx; i < end_idx; i += step)
     {
       int peak = peak_tuple[i].to_int ();
@@ -364,15 +367,15 @@
         int end = end_tuple[i].to_int ();
         if (unlikely (start > peak || peak > end ||
                       (start < 0 && end > 0 && peak))) continue;
-        if (v < start || v > end) return 0.f;
+        if (v < start || v > end) return 0.0;
         if (v < peak)
-        { if (peak != start) scalar *= (float) (v - start) / (peak - start); }
+        { if (peak != start) scalar *= (double) (v - start) / (peak - start); }
         else
-        { if (peak != end) scalar *= (float) (end - v) / (end - peak); }
+        { if (peak != end) scalar *= (double) (end - v) / (end - peak); }
       }
-      else if (!v || v < hb_min (0, peak) || v > hb_max (0, peak)) return 0.f;
+      else if (!v || v < hb_min (0, peak) || v > hb_max (0, peak)) return 0.0;
       else
-        scalar *= (float) v / peak;
+        scalar *= (double) v / peak;
     }
     return scalar;
   }
@@ -434,15 +437,17 @@
 
 struct tuple_delta_t
 {
+  static constexpr bool realloc_move = true;  // Watch out when adding new members!
+
   public:
   hb_hashmap_t<hb_tag_t, Triple> axis_tuples;
 
   /* indices_length = point_count, indice[i] = 1 means point i is referenced */
   hb_vector_t<bool> indices;
-  
-  hb_vector_t<float> deltas_x;
+
+  hb_vector_t<double> deltas_x;
   /* empty for cvar tuples */
-  hb_vector_t<float> deltas_y;
+  hb_vector_t<double> deltas_y;
 
   /* compiled data: header and deltas
    * compiled point data is saved in a hashmap within tuple_variations_t cause
@@ -456,7 +461,7 @@
   tuple_delta_t () = default;
   tuple_delta_t (const tuple_delta_t& o) = default;
 
-  friend void swap (tuple_delta_t& a, tuple_delta_t& b)
+  friend void swap (tuple_delta_t& a, tuple_delta_t& b) noexcept
   {
     hb_swap (a.axis_tuples, b.axis_tuples);
     hb_swap (a.indices, b.indices);
@@ -467,10 +472,10 @@
     hb_swap (a.compiled_peak_coords, b.compiled_peak_coords);
   }
 
-  tuple_delta_t (tuple_delta_t&& o) : tuple_delta_t ()
+  tuple_delta_t (tuple_delta_t&& o)  noexcept : tuple_delta_t ()
   { hb_swap (*this, o); }
 
-  tuple_delta_t& operator = (tuple_delta_t&& o)
+  tuple_delta_t& operator = (tuple_delta_t&& o) noexcept
   {
     hb_swap (*this, o);
     return *this;
@@ -508,20 +513,25 @@
     return *this;
   }
 
-  tuple_delta_t& operator *= (float scalar)
+  tuple_delta_t& operator *= (double scalar)
   {
-    if (scalar == 1.0f)
+    if (scalar == 1.0)
       return *this;
 
     unsigned num = indices.length;
-    for (unsigned i = 0; i < num; i++)
-    {
-      if (!indices.arrayZ[i]) continue;
-
-      deltas_x[i] *= scalar;
-      if (deltas_y)
-        deltas_y[i] *= scalar;
-    }
+    if (deltas_y)
+      for (unsigned i = 0; i < num; i++)
+      {
+	if (!indices.arrayZ[i]) continue;
+	deltas_x[i] *= scalar;
+	deltas_y[i] *= scalar;
+      }
+    else
+      for (unsigned i = 0; i < num; i++)
+      {
+	if (!indices.arrayZ[i]) continue;
+	deltas_x[i] *= scalar;
+      }
     return *this;
   }
 
@@ -536,18 +546,18 @@
       return out;
     }
 
-    if ((tent->minimum < 0.f && tent->maximum > 0.f) ||
+    if ((tent->minimum < 0.0 && tent->maximum > 0.0) ||
         !(tent->minimum <= tent->middle && tent->middle <= tent->maximum))
       return out;
 
-    if (tent->middle == 0.f)
+    if (tent->middle == 0.0)
     {
       out.push (*this);
       return out;
     }
 
-    result_t solutions = rebase_tent (*tent, axis_limit, axis_triple_distances);
-    for (auto t : solutions)
+    rebase_tent_result_t solutions = rebase_tent (*tent, axis_limit, axis_triple_distances);
+    for (auto &t : solutions)
     {
       tuple_delta_t new_var = *this;
       if (t.second == Triple ())
@@ -600,7 +610,9 @@
                                  const hb_map_t& axes_old_index_tag_map,
                                  const hb_hashmap_t<const hb_vector_t<char>*, unsigned>* shared_tuples_idx_map)
   {
-    if (!compiled_deltas) return false;
+    /* compiled_deltas could be empty after iup delta optimization, we can skip
+     * compiling this tuple and return true */
+    if (!compiled_deltas) return true;
 
     unsigned cur_axis_count = axes_index_map.get_population ();
     /* allocate enough memory: 1 peak + 2 intermediate coords + fixed header size */
@@ -714,22 +726,28 @@
   }
 
   bool compile_deltas ()
+  { return compile_deltas (indices, deltas_x, deltas_y, compiled_deltas); }
+
+  bool compile_deltas (const hb_vector_t<bool> &point_indices,
+                       const hb_vector_t<double> &x_deltas,
+                       const hb_vector_t<double> &y_deltas,
+                       hb_vector_t<char> &compiled_deltas /* OUT */)
   {
     hb_vector_t<int> rounded_deltas;
-    if (unlikely (!rounded_deltas.alloc (indices.length)))
+    if (unlikely (!rounded_deltas.alloc (point_indices.length)))
       return false;
 
-    for (unsigned i = 0; i < indices.length; i++)
+    for (unsigned i = 0; i < point_indices.length; i++)
     {
-      if (!indices[i]) continue;
-      int rounded_delta = (int) roundf (deltas_x[i]);
+      if (!point_indices[i]) continue;
+      int rounded_delta = (int) roundf (x_deltas.arrayZ[i]);
       rounded_deltas.push (rounded_delta);
     }
 
-    if (!rounded_deltas) return false;
+    if (!rounded_deltas) return true;
     /* allocate enough memories 3 * num_deltas */
     unsigned alloc_len = 3 * rounded_deltas.length;
-    if (deltas_y)
+    if (y_deltas)
       alloc_len *= 2;
 
     if (unlikely (!compiled_deltas.resize (alloc_len))) return false;
@@ -737,14 +755,14 @@
     unsigned i = 0;
     unsigned encoded_len = encode_delta_run (i, compiled_deltas.as_array (), rounded_deltas);
 
-    if (deltas_y)
+    if (y_deltas)
     {
-      /* reuse the rounded_deltas vector, check that deltas_y have the same num of deltas as deltas_x */
+      /* reuse the rounded_deltas vector, check that y_deltas have the same num of deltas as x_deltas */
       unsigned j = 0;
-      for (unsigned idx = 0; idx < indices.length; idx++)
+      for (unsigned idx = 0; idx < point_indices.length; idx++)
       {
-        if (!indices[idx]) continue;
-        int rounded_delta = (int) roundf (deltas_y[idx]);
+        if (!point_indices[idx]) continue;
+        int rounded_delta = (int) roundf (y_deltas.arrayZ[idx]);
 
         if (j >= rounded_deltas.length) return false;
 
@@ -752,7 +770,7 @@
       }
 
       if (j != rounded_deltas.length) return false;
-      /* reset i because we reuse rounded_deltas for deltas_y */
+      /* reset i because we reuse rounded_deltas for y_deltas */
       i = 0;
       encoded_len += encode_delta_run (i, compiled_deltas.as_array ().sub_array (encoded_len), rounded_deltas);
     }
@@ -767,7 +785,7 @@
     unsigned encoded_len = 0;
     while (i < num_deltas)
     {
-      int val = deltas[i];
+      int val = deltas.arrayZ[i];
       if (val == 0)
         encoded_len += encode_delta_run_as_zeroes (i, encoded_bytes.sub_array (encoded_len), deltas);
       else if (val >= -128 && val <= 127)
@@ -786,7 +804,7 @@
     unsigned run_length = 0;
     auto it = encoded_bytes.iter ();
     unsigned encoded_len = 0;
-    while (i < num_deltas && deltas[i] == 0)
+    while (i < num_deltas && deltas.arrayZ[i] == 0)
     {
       i++;
       run_length++;
@@ -815,13 +833,13 @@
     unsigned num_deltas = deltas.length;
     while (i < num_deltas)
     {
-      int val = deltas[i];
+      int val = deltas.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_deltas && deltas[i+1] == 0)
+      if (val == 0 && i + 1 < num_deltas && deltas.arrayZ[i+1] == 0)
         break;
 
       i++;
@@ -838,7 +856,7 @@
 
       for (unsigned j = 0; j < 64; j++)
       {
-        *it++ = static_cast<char> (deltas[start + j]);
+        *it++ = static_cast<char> (deltas.arrayZ[start + j]);
         encoded_len++;
       }
 
@@ -853,7 +871,7 @@
 
       while (start < i)
       {
-        *it++ = static_cast<char> (deltas[start++]);
+        *it++ = static_cast<char> (deltas.arrayZ[start++]);
         encoded_len++;
       }
     }
@@ -869,8 +887,8 @@
     unsigned num_deltas = deltas.length;
     while (i < num_deltas)
     {
-      int val = deltas[i];
-      
+      int val = deltas.arrayZ[i];
+
       /* start a new run for a single zero value*/
       if (val == 0) break;
 
@@ -879,7 +897,7 @@
        * Only start a new run when there're 2 continuous such values. */
       if (val >= -128 && val <= 127 &&
           i + 1 < num_deltas &&
-          deltas[i+1] >= -128 && deltas[i+1] <= 127)
+          deltas.arrayZ[i+1] >= -128 && deltas.arrayZ[i+1] <= 127)
         break;
 
       i++;
@@ -895,7 +913,7 @@
 
       for (unsigned j = 0; j < 64; j++)
       {
-        int16_t delta_val = deltas[start + j];
+        int16_t delta_val = deltas.arrayZ[start + j];
         *it++ = static_cast<char> (delta_val >> 8);
         *it++ = static_cast<char> (delta_val & 0xFF);
 
@@ -912,7 +930,7 @@
       encoded_len++;
       while (start < i)
       {
-        int16_t delta_val = deltas[start++];
+        int16_t delta_val = deltas.arrayZ[start++];
         *it++ = static_cast<char> (delta_val >> 8);
         *it++ = static_cast<char> (delta_val & 0xFF);
 
@@ -982,9 +1000,13 @@
         {
           i = next_index (i, start_point, end_point);
           if (i == next) break;
-          deltas_x.arrayZ[i] = infer_delta (orig_points.arrayZ[i].x, orig_points.arrayZ[prev].x, orig_points.arrayZ[next].x,
+          deltas_x.arrayZ[i] = infer_delta ((double) orig_points.arrayZ[i].x,
+                                            (double) orig_points.arrayZ[prev].x,
+                                            (double) orig_points.arrayZ[next].x,
                                             deltas_x.arrayZ[prev], deltas_x.arrayZ[next]);
-          deltas_y.arrayZ[i] = infer_delta (orig_points.arrayZ[i].y, orig_points.arrayZ[prev].y, orig_points.arrayZ[next].y,
+          deltas_y.arrayZ[i] = infer_delta ((double) orig_points.arrayZ[i].y,
+                                            (double) orig_points.arrayZ[prev].y,
+                                            (double) orig_points.arrayZ[next].y,
                                             deltas_y.arrayZ[prev], deltas_y.arrayZ[next]);
           inferred_idxes.add (i);
           if (--unref_count == 0) goto no_more_gaps;
@@ -1002,8 +1024,8 @@
       {
         if (!inferred_idxes.has (i))
         {
-          deltas_x.arrayZ[i] = 0.f;
-          deltas_y.arrayZ[i] = 0.f;
+          deltas_x.arrayZ[i] = 0.0;
+          deltas_y.arrayZ[i] = 0.0;
         }
         indices[i] = true;
       }
@@ -1011,16 +1033,181 @@
     return true;
   }
 
-  static float infer_delta (float target_val, float prev_val, float next_val, float prev_delta, float next_delta)
+  bool optimize (const contour_point_vector_t& contour_points,
+                 bool is_composite,
+                 double tolerance = 0.5 + 1e-10)
+  {
+    unsigned count = contour_points.length;
+    if (deltas_x.length != count ||
+        deltas_y.length != count)
+      return false;
+
+    hb_vector_t<bool> opt_indices;
+    hb_vector_t<int> rounded_x_deltas, rounded_y_deltas;
+
+    if (unlikely (!rounded_x_deltas.alloc (count) ||
+                  !rounded_y_deltas.alloc (count)))
+      return false;
+
+    for (unsigned i = 0; i < count; i++)
+    {
+      int rounded_x_delta = (int) roundf (deltas_x.arrayZ[i]);
+      int rounded_y_delta = (int) roundf (deltas_y.arrayZ[i]);
+      rounded_x_deltas.push (rounded_x_delta);
+      rounded_y_deltas.push (rounded_y_delta);
+    }
+
+    if (!iup_delta_optimize (contour_points, rounded_x_deltas, rounded_y_deltas, opt_indices, tolerance))
+      return false;
+
+    unsigned ref_count = 0;
+    for (bool ref_flag : opt_indices)
+       ref_count += ref_flag;
+
+    if (ref_count == count) return true;
+
+    hb_vector_t<double> opt_deltas_x, opt_deltas_y;
+    bool is_comp_glyph_wo_deltas = (is_composite && ref_count == 0);
+    if (is_comp_glyph_wo_deltas)
+    {
+      if (unlikely (!opt_deltas_x.resize (count) ||
+                    !opt_deltas_y.resize (count)))
+        return false;
+
+      opt_indices.arrayZ[0] = true;
+      for (unsigned i = 1; i < count; i++)
+        opt_indices.arrayZ[i] = false;
+    }
+
+    hb_vector_t<char> opt_point_data;
+    if (!compile_point_set (opt_indices, opt_point_data))
+      return false;
+    hb_vector_t<char> opt_deltas_data;
+    if (!compile_deltas (opt_indices,
+                         is_comp_glyph_wo_deltas ? opt_deltas_x : deltas_x,
+                         is_comp_glyph_wo_deltas ? opt_deltas_y : deltas_y,
+                         opt_deltas_data))
+      return false;
+
+    hb_vector_t<char> point_data;
+    if (!compile_point_set (indices, point_data))
+      return false;
+    hb_vector_t<char> deltas_data;
+    if (!compile_deltas (indices, deltas_x, deltas_y, deltas_data))
+      return false;
+
+    if (opt_point_data.length + opt_deltas_data.length < point_data.length + deltas_data.length)
+    {
+      indices.fini ();
+      indices = std::move (opt_indices);
+
+      if (is_comp_glyph_wo_deltas)
+      {
+        deltas_x.fini ();
+        deltas_x = std::move (opt_deltas_x);
+
+        deltas_y.fini ();
+        deltas_y = std::move (opt_deltas_y);
+      }
+    }
+    return !indices.in_error () && !deltas_x.in_error () && !deltas_y.in_error ();
+  }
+
+  static bool compile_point_set (const hb_vector_t<bool> &point_indices,
+                                 hb_vector_t<char>& compiled_points /* OUT */)
+  {
+    unsigned num_points = 0;
+    for (bool i : point_indices)
+      if (i) num_points++;
+
+    /* when iup optimization is enabled, num of referenced points could be 0 */
+    if (!num_points) return true;
+
+    unsigned indices_length = point_indices.length;
+    /* If the points set consists of all points in the glyph, it's encoded with a
+     * single zero byte */
+    if (num_points == indices_length)
+      return compiled_points.resize (1);
+
+    /* allocate enough memories: 2 bytes for count + 3 bytes for each point */
+    unsigned num_bytes = 2 + 3 *num_points;
+    if (unlikely (!compiled_points.resize (num_bytes, false)))
+      return false;
+
+    unsigned pos = 0;
+    /* binary data starts with the total number of reference points */
+    if (num_points < 0x80)
+      compiled_points.arrayZ[pos++] = num_points;
+    else
+    {
+      compiled_points.arrayZ[pos++] = ((num_points >> 8) | 0x80);
+      compiled_points.arrayZ[pos++] = num_points & 0xFF;
+    }
+
+    const unsigned max_run_length = 0x7F;
+    unsigned i = 0;
+    unsigned last_value = 0;
+    unsigned num_encoded = 0;
+    while (i < indices_length && num_encoded < num_points)
+    {
+      unsigned run_length = 0;
+      unsigned header_pos = pos;
+      compiled_points.arrayZ[pos++] = 0;
+
+      bool use_byte_encoding = false;
+      bool new_run = true;
+      while (i < indices_length && num_encoded < num_points &&
+             run_length <= max_run_length)
+      {
+        // find out next referenced point index
+        while (i < indices_length && !point_indices[i])
+          i++;
+
+        if (i >= indices_length) break;
+
+        unsigned cur_value = i;
+        unsigned delta = cur_value - last_value;
+
+        if (new_run)
+        {
+          use_byte_encoding = (delta <= 0xFF);
+          new_run = false;
+        }
+
+        if (use_byte_encoding && delta > 0xFF)
+          break;
+
+        if (use_byte_encoding)
+          compiled_points.arrayZ[pos++] = delta;
+        else
+        {
+          compiled_points.arrayZ[pos++] = delta >> 8;
+          compiled_points.arrayZ[pos++] = delta & 0xFF;
+        }
+        i++;
+        last_value = cur_value;
+        run_length++;
+        num_encoded++;
+      }
+
+      if (use_byte_encoding)
+        compiled_points.arrayZ[header_pos] = run_length - 1;
+      else
+        compiled_points.arrayZ[header_pos] = (run_length - 1) | 0x80;
+    }
+    return compiled_points.resize (pos, false);
+  }
+
+  static double infer_delta (double target_val, double prev_val, double next_val, double prev_delta, double next_delta)
   {
     if (prev_val == next_val)
-      return (prev_delta == next_delta) ? prev_delta : 0.f;
+      return (prev_delta == next_delta) ? prev_delta : 0.0;
     else if (target_val <= hb_min (prev_val, next_val))
       return (prev_val < next_val) ? prev_delta : next_delta;
     else if (target_val >= hb_max (prev_val, next_val))
       return (prev_val > next_val) ? prev_delta : next_delta;
 
-    float r = (target_val - prev_val) / (next_val - prev_val);
+    double r = (target_val - prev_val) / (next_val - prev_val);
     return prev_delta + r * (next_delta - prev_delta);
   }
 
@@ -1062,41 +1249,41 @@
 
     private:
     /* referenced point set->compiled point data map */
-    hb_hashmap_t<const hb_vector_t<bool>*, hb_bytes_t> point_data_map;
+    hb_hashmap_t<const hb_vector_t<bool>*, hb_vector_t<char>> point_data_map;
     /* referenced point set-> count map, used in finding shared points */
     hb_hashmap_t<const hb_vector_t<bool>*, unsigned> point_set_count_map;
 
     /* empty for non-gvar tuples.
-     * shared_points_bytes is just a copy of some value in the point_data_map,
+     * shared_points_bytes is a pointer to some value in the point_data_map,
      * which will be freed during map destruction. Save it for serialization, so
      * no need to do find_shared_points () again */
-    hb_bytes_t shared_points_bytes;
+    hb_vector_t<char> *shared_points_bytes = nullptr;
 
     /* total compiled byte size as TupleVariationData format, initialized to its
      * min_size: 4 */
     unsigned compiled_byte_size = 4;
 
+    /* for gvar iup delta optimization: whether this is a composite glyph */
+    bool is_composite = false;
+
     public:
     tuple_variations_t () = default;
     tuple_variations_t (const tuple_variations_t&) = delete;
     tuple_variations_t& operator=(const tuple_variations_t&) = delete;
     tuple_variations_t (tuple_variations_t&&) = default;
     tuple_variations_t& operator=(tuple_variations_t&&) = default;
-    ~tuple_variations_t () { fini (); }
-    void fini ()
-    {
-      for (auto _ : point_data_map.values ())
-        _.fini ();
-
-      point_set_count_map.fini ();
-      tuple_vars.fini ();
-    }
+    ~tuple_variations_t () = default;
 
     explicit operator bool () const { return bool (tuple_vars); }
     unsigned get_var_count () const
     {
-      unsigned count = tuple_vars.length;
-      if (shared_points_bytes.length)
+      unsigned count = 0;
+      /* when iup delta opt is enabled, compiled_deltas could be empty and we
+       * should skip this tuple */
+      for (auto& tuple: tuple_vars)
+        if (tuple.compiled_deltas) count++;
+
+      if (shared_points_bytes && shared_points_bytes->length)
         count |= TupleVarCount::SharedPointNumbers;
       return count;
     }
@@ -1110,26 +1297,27 @@
                                      bool is_gvar,
                                      const hb_map_t *axes_old_index_tag_map,
                                      const hb_vector_t<unsigned> &shared_indices,
-                                     const hb_array_t<const F2DOT14> shared_tuples)
+                                     const hb_array_t<const F2DOT14> shared_tuples,
+                                     bool is_composite_glyph)
     {
       do
       {
         const HBUINT8 *p = iterator.get_serialized_data ();
         unsigned int length = iterator.current_tuple->get_data_size ();
         if (unlikely (!iterator.var_data_bytes.check_range (p, length)))
-        { fini (); return false; }
+          return false;
 
         hb_hashmap_t<hb_tag_t, Triple> axis_tuples;
         if (!iterator.current_tuple->unpack_axis_tuples (iterator.get_axis_count (), shared_tuples, axes_old_index_tag_map, axis_tuples)
             || axis_tuples.is_empty ())
-        { fini (); return false; }
+          return false;
 
         hb_vector_t<unsigned> private_indices;
         bool has_private_points = iterator.current_tuple->has_private_points ();
         const HBUINT8 *end = p + length;
         if (has_private_points &&
             !TupleVariationData::unpack_points (p, private_indices, end))
-        { fini (); return false; }
+          return false;
 
         const hb_vector_t<unsigned> &indices = has_private_points ? private_indices : shared_indices;
         bool apply_to_all = (indices.length == 0);
@@ -1139,55 +1327,59 @@
 
         if (unlikely (!deltas_x.resize (num_deltas, false) ||
                       !TupleVariationData::unpack_deltas (p, deltas_x, end)))
-        { fini (); return false; }
+          return false;
 
         hb_vector_t<int> deltas_y;
         if (is_gvar)
         {
           if (unlikely (!deltas_y.resize (num_deltas, false) ||
                         !TupleVariationData::unpack_deltas (p, deltas_y, end)))
-          { fini (); return false; }
+            return false;
         }
 
         tuple_delta_t var;
         var.axis_tuples = std::move (axis_tuples);
         if (unlikely (!var.indices.resize (point_count) ||
                       !var.deltas_x.resize (point_count, false)))
-        { fini (); return false; }
+          return false;
 
         if (is_gvar && unlikely (!var.deltas_y.resize (point_count, false)))
-        { fini (); return false; }
+          return false;
 
         for (unsigned i = 0; i < num_deltas; i++)
         {
           unsigned idx = apply_to_all ? i : indices[i];
           if (idx >= point_count) continue;
           var.indices[idx] = true;
-          var.deltas_x[idx] = static_cast<float> (deltas_x[i]);
+          var.deltas_x[idx] = deltas_x[i];
           if (is_gvar)
-            var.deltas_y[idx] = static_cast<float> (deltas_y[i]);
+            var.deltas_y[idx] = deltas_y[i];
         }
         tuple_vars.push (std::move (var));
       } while (iterator.move_to_next ());
+
+      is_composite = is_composite_glyph;
       return true;
     }
 
     bool create_from_item_var_data (const VarData &var_data,
                                     const hb_vector_t<hb_hashmap_t<hb_tag_t, Triple>>& regions,
                                     const hb_map_t& axes_old_index_tag_map,
+                                    unsigned& item_count,
                                     const hb_inc_bimap_t* inner_map = nullptr)
     {
       /* NULL offset, to keep original varidx valid, just return */
       if (&var_data == &Null (VarData))
         return true;
-  
+
       unsigned num_regions = var_data.get_region_index_count ();
       if (!tuple_vars.alloc (num_regions)) return false;
-  
-      unsigned item_count = inner_map ? inner_map->get_population () : var_data.get_item_count ();
+
+      item_count = inner_map ? inner_map->get_population () : var_data.get_item_count ();
+      if (!item_count) return true;
       unsigned row_size = var_data.get_row_size ();
       const HBUINT8 *delta_bytes = var_data.get_delta_bytes ();
-  
+
       for (unsigned r = 0; r < num_regions; r++)
       {
         /* In VarData, deltas are organized in rows, convert them into
@@ -1196,14 +1388,14 @@
         if (!tuple.deltas_x.resize (item_count, false) ||
             !tuple.indices.resize (item_count, false))
           return false;
-  
+
         for (unsigned i = 0; i < item_count; i++)
         {
           tuple.indices.arrayZ[i] = true;
           tuple.deltas_x.arrayZ[i] = var_data.get_item_delta_fast (inner_map ? inner_map->backward (i) : i,
                                                                    r, delta_bytes, row_size);
         }
-  
+
         unsigned region_index = var_data.get_region_index (r);
         if (region_index >= regions.length) return false;
         tuple.axis_tuples = regions.arrayZ[region_index];
@@ -1237,7 +1429,7 @@
         Triple *axis_limit;
         if (!normalized_axes_location.has (axis_tag, &axis_limit))
           return false;
-        TripleDistances axis_triple_distances{1.f, 1.f};
+        TripleDistances axis_triple_distances{1.0, 1.0};
         if (axes_triple_distances.has (axis_tag))
           axis_triple_distances = axes_triple_distances.get (axis_tag);
 
@@ -1250,7 +1442,7 @@
           unsigned new_len = new_vars.length + out.length;
 
           if (unlikely (!new_vars.alloc (new_len, false)))
-          { fini (); return false;}
+            return false;
 
           for (unsigned i = 0; i < out.length; i++)
             new_vars.push (std::move (out[i]));
@@ -1261,8 +1453,9 @@
       return true;
     }
 
-    /* merge tuple variations with overlapping tents */
-    void merge_tuple_variations ()
+    /* merge tuple variations with overlapping tents, if iup delta optimization
+     * is enabled, add default deltas to contour_points */
+    bool merge_tuple_variations (contour_point_vector_t* contour_points = nullptr)
     {
       hb_vector_t<tuple_delta_t> new_vars;
       hb_hashmap_t<const hb_hashmap_t<hb_tag_t, Triple>*, unsigned> m;
@@ -1270,7 +1463,15 @@
       for (const tuple_delta_t& var : tuple_vars)
       {
         /* if all axes are pinned, drop the tuple variation */
-        if (var.axis_tuples.is_empty ()) continue;
+        if (var.axis_tuples.is_empty ())
+        {
+          /* if iup_delta_optimize is enabled, add deltas to contour coords */
+          if (contour_points && !contour_points->add_deltas (var.deltas_x,
+                                                             var.deltas_y,
+                                                             var.indices))
+            return false;
+          continue;
+        }
 
         unsigned *idx;
         if (m.has (&(var.axis_tuples), &idx))
@@ -1280,98 +1481,14 @@
         else
         {
           new_vars.push (var);
-          m.set (&(var.axis_tuples), i);
+          if (!m.set (&(var.axis_tuples), i))
+            return false;
           i++;
         }
       }
       tuple_vars.fini ();
       tuple_vars = std::move (new_vars);
-    }
-
-    hb_bytes_t compile_point_set (const hb_vector_t<bool> &point_indices)
-    {
-      unsigned num_points = 0;
-      for (bool i : point_indices)
-        if (i) num_points++;
-
-      unsigned indices_length = point_indices.length;
-      /* If the points set consists of all points in the glyph, it's encoded with a
-       * single zero byte */
-      if (num_points == indices_length)
-      {
-        char *p = (char *) hb_calloc (1, sizeof (char));
-        if (unlikely (!p)) return hb_bytes_t ();
-
-        return hb_bytes_t (p, 1);
-      }
-
-      /* allocate enough memories: 2 bytes for count + 3 bytes for each point */
-      unsigned num_bytes = 2 + 3 *num_points;
-      char *p = (char *) hb_calloc (num_bytes, sizeof (char));
-      if (unlikely (!p)) return hb_bytes_t ();
-
-      unsigned pos = 0;
-      /* binary data starts with the total number of reference points */
-      if (num_points < 0x80)
-        p[pos++] = num_points;
-      else
-      {
-        p[pos++] = ((num_points >> 8) | 0x80);
-        p[pos++] = num_points & 0xFF;
-      }
-
-      const unsigned max_run_length = 0x7F;
-      unsigned i = 0;
-      unsigned last_value = 0;
-      unsigned num_encoded = 0;
-      while (i < indices_length && num_encoded < num_points)
-      {
-        unsigned run_length = 0;
-        unsigned header_pos = pos;
-        p[pos++] = 0;
-
-        bool use_byte_encoding = false;
-        bool new_run = true;
-        while (i < indices_length && num_encoded < num_points &&
-               run_length <= max_run_length)
-        {
-          // find out next referenced point index
-          while (i < indices_length && !point_indices[i])
-            i++;
-
-          if (i >= indices_length) break;
-
-          unsigned cur_value = i;
-          unsigned delta = cur_value - last_value;
-
-          if (new_run)
-          {
-            use_byte_encoding = (delta <= 0xFF);
-            new_run = false;
-          }
-
-          if (use_byte_encoding && delta > 0xFF)
-            break;
-
-          if (use_byte_encoding)
-            p[pos++] = delta;
-          else
-          {
-            p[pos++] = delta >> 8;
-            p[pos++] = delta & 0xFF;
-          }
-          i++;
-          last_value = cur_value;
-          run_length++;
-          num_encoded++;
-        }
-
-        if (use_byte_encoding)
-          p[header_pos] = run_length - 1;
-        else
-          p[header_pos] = (run_length - 1) | 0x80;
-      }
-      return hb_bytes_t (p, pos);
+      return true;
     }
 
     /* compile all point set and store byte data in a point_set->hb_bytes_t hashmap,
@@ -1390,12 +1507,12 @@
             return false;
           continue;
         }
-        
-        hb_bytes_t compiled_data = compile_point_set (*points_set);
-        if (unlikely (compiled_data == hb_bytes_t ()))
+
+        hb_vector_t<char> compiled_point_data;
+        if (!tuple_delta_t::compile_point_set (*points_set, compiled_point_data))
           return false;
-        
-        if (!point_data_map.set (points_set, compiled_data) ||
+
+        if (!point_data_map.set (points_set, std::move (compiled_point_data)) ||
             !point_set_count_map.set (points_set, 1))
           return false;
       }
@@ -1403,43 +1520,56 @@
     }
 
     /* find shared points set which saves most bytes */
-    hb_bytes_t find_shared_points ()
+    void find_shared_points ()
     {
       unsigned max_saved_bytes = 0;
-      hb_bytes_t res{};
 
-      for (const auto& _ : point_data_map.iter ())
+      for (const auto& _ : point_data_map.iter_ref ())
       {
         const hb_vector_t<bool>* points_set = _.first;
         unsigned data_length = _.second.length;
+        if (!data_length) continue;
         unsigned *count;
         if (unlikely (!point_set_count_map.has (points_set, &count) ||
                       *count <= 1))
-          return hb_bytes_t ();
+        {
+          shared_points_bytes = nullptr;
+          return;
+        }
 
         unsigned saved_bytes = data_length * ((*count) -1);
         if (saved_bytes > max_saved_bytes)
         {
           max_saved_bytes = saved_bytes;
-          res = _.second;
+          shared_points_bytes = &(_.second);
         }
       }
-      return res;
     }
 
-    bool calc_inferred_deltas (contour_point_vector_t& contour_points)
+    bool calc_inferred_deltas (const contour_point_vector_t& contour_points)
     {
       for (tuple_delta_t& var : tuple_vars)
         if (!var.calc_inferred_deltas (contour_points))
           return false;
-      
+
+      return true;
+    }
+
+    bool iup_optimize (const contour_point_vector_t& contour_points)
+    {
+      for (tuple_delta_t& var : tuple_vars)
+      {
+        if (!var.optimize (contour_points, is_composite))
+          return false;
+      }
       return true;
     }
 
     public:
     bool instantiate (const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location,
                       const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances,
-                      contour_point_vector_t* contour_points = nullptr)
+                      contour_point_vector_t* contour_points = nullptr,
+                      bool optimize = false)
     {
       if (!tuple_vars) return true;
       if (!change_tuple_variations_axis_limits (normalized_axes_location, axes_triple_distances))
@@ -1449,7 +1579,14 @@
         if (!calc_inferred_deltas (*contour_points))
           return false;
 
-      merge_tuple_variations ();
+      /* if iup delta opt is on, contour_points can't be null */
+      if (optimize && !contour_points)
+        return false;
+
+      if (!merge_tuple_variations (optimize ? contour_points : nullptr))
+        return false;
+
+      if (optimize && !iup_optimize (*contour_points)) return false;
       return !tuple_vars.in_error ();
     }
 
@@ -1464,21 +1601,27 @@
 
       if (use_shared_points)
       {
-        shared_points_bytes = find_shared_points ();
-        compiled_byte_size += shared_points_bytes.length;
+        find_shared_points ();
+        if (shared_points_bytes)
+          compiled_byte_size += shared_points_bytes->length;
       }
       // compile delta and tuple var header for each tuple variation
       for (auto& tuple: tuple_vars)
       {
         const hb_vector_t<bool>* points_set = &(tuple.indices);
-        hb_bytes_t *points_data;
+        hb_vector_t<char> *points_data;
         if (unlikely (!point_data_map.has (points_set, &points_data)))
           return false;
 
+        /* when iup optimization is enabled, num of referenced points could be 0
+         * and thus the compiled points bytes is empty, we should skip compiling
+         * this tuple */
+        if (!points_data->length)
+          continue;
         if (!tuple.compile_deltas ())
           return false;
 
-        unsigned points_data_length = (*points_data != shared_points_bytes) ? points_data->length : 0;
+        unsigned points_data_length = (points_data != shared_points_bytes) ? points_data->length : 0;
         if (!tuple.compile_tuple_var_header (axes_index_map, points_data_length, axes_old_index_tag_map,
                                              shared_tuples_idx_map))
           return false;
@@ -1502,18 +1645,24 @@
     bool serialize_var_data (hb_serialize_context_t *c, bool is_gvar) const
     {
       TRACE_SERIALIZE (this);
-      if (is_gvar)
-        shared_points_bytes.copy (c);
+      if (is_gvar && shared_points_bytes)
+      {
+        hb_bytes_t s (shared_points_bytes->arrayZ, shared_points_bytes->length);
+        s.copy (c);
+      }
 
       for (const auto& tuple: tuple_vars)
       {
         const hb_vector_t<bool>* points_set = &(tuple.indices);
-        hb_bytes_t *point_data;
+        hb_vector_t<char> *point_data;
         if (!point_data_map.has (points_set, &point_data))
           return_trace (false);
 
-        if (!is_gvar || *point_data != shared_points_bytes)
-          point_data->copy (c);
+        if (!is_gvar || point_data != shared_points_bytes)
+        {
+          hb_bytes_t s (point_data->arrayZ, point_data->length);
+          s.copy (c);
+        }
 
         tuple.compiled_deltas.as_array ().copy (c);
         if (c->in_error ()) return_trace (false);
@@ -1700,13 +1849,15 @@
                                    const hb_map_t *axes_old_index_tag_map,
                                    const hb_vector_t<unsigned> &shared_indices,
                                    const hb_array_t<const F2DOT14> shared_tuples,
-                                   tuple_variations_t& tuple_variations /* OUT */) const
+                                   tuple_variations_t& tuple_variations, /* OUT */
+                                   bool is_composite_glyph = false) const
   {
     return tuple_variations.create_from_tuple_var_data (iterator, tupleVarCount,
                                                         point_count, is_gvar,
                                                         axes_old_index_tag_map,
                                                         shared_indices,
-                                                        shared_tuples);
+                                                        shared_tuples,
+                                                        is_composite_glyph);
   }
 
   bool serialize (hb_serialize_context_t *c,
@@ -1727,7 +1878,7 @@
 
     if (!tuple_variations.serialize_var_headers (c, total_header_len))
       return_trace (false);
-    
+
     unsigned data_offset = min_size + total_header_len;
     if (!is_gvar) data_offset += 4;
     if (!c->check_assign (out->data, data_offset, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
@@ -1775,6 +1926,14 @@
    * have the same num of deltas (rows) */
   hb_vector_t<tuple_variations_t> vars;
 
+  /* num of retained rows for each subtable, there're 2 cases when var_data is empty:
+   * 1. retained item_count is zero
+   * 2. regions is empty and item_count is non-zero.
+   * when converting to tuples, both will be dropped because the tuple is empty,
+   * however, we need to retain 2. as all-zero rows to keep original varidx
+   * valid, so we need a way to remember the num of rows for each subtable */
+  hb_vector_t<unsigned> var_data_num_rows;
+
   /* original region list, decompiled from item varstore, used when rebuilding
    * region list after instantiation */
   hb_vector_t<hb_hashmap_t<hb_tag_t, Triple>> orig_region_list;
@@ -1812,7 +1971,7 @@
   const hb_map_t& get_varidx_map () const
   { return varidx_map; }
 
-  bool instantiate (const VariationStore& varStore,
+  bool instantiate (const ItemVariationStore& varStore,
                     const hb_subset_plan_t *plan,
                     bool optimize=true,
                     bool use_no_variation_idx=true,
@@ -1826,7 +1985,7 @@
   }
 
   /* keep below APIs public only for unit test: test-item-varstore */
-  bool create_from_item_varstore (const VariationStore& varStore,
+  bool create_from_item_varstore (const ItemVariationStore& varStore,
                                   const hb_map_t& axes_old_index_tag_map,
                                   const hb_array_t <const hb_inc_bimap_t> inner_maps = hb_array_t<const hb_inc_bimap_t> ())
   {
@@ -1836,22 +1995,26 @@
 
     unsigned num_var_data = varStore.get_sub_table_count ();
     if (inner_maps && inner_maps.length != num_var_data) return false;
-    if (!vars.alloc (num_var_data)) return false;
+    if (!vars.alloc (num_var_data) ||
+        !var_data_num_rows.alloc (num_var_data)) return false;
 
     for (unsigned i = 0; i < num_var_data; i++)
     {
       if (inner_maps && !inner_maps.arrayZ[i].get_population ())
           continue;
       tuple_variations_t var_data_tuples;
+      unsigned item_count = 0;
       if (!var_data_tuples.create_from_item_var_data (varStore.get_sub_table (i),
                                                       orig_region_list,
                                                       axes_old_index_tag_map,
+                                                      item_count,
                                                       inner_maps ? &(inner_maps.arrayZ[i]) : nullptr))
         return false;
 
+      var_data_num_rows.push (item_count);
       vars.push (std::move (var_data_tuples));
     }
-    return !vars.in_error ();
+    return !vars.in_error () && !var_data_num_rows.in_error () && vars.length == var_data_num_rows.length;
   }
 
   bool instantiate_tuple_vars (const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location,
@@ -1973,12 +2136,8 @@
     unsigned num_cols = region_list.length;
     /* pre-alloc a 2D vector for all sub_table's VarData rows */
     unsigned total_rows = 0;
-    for (unsigned major = 0; major < vars.length; major++)
-    {
-      const tuple_variations_t& tuples = vars[major];
-      /* all tuples in each sub_table should have same num of deltas(num rows) */
-      total_rows += tuples.tuple_vars[0].deltas_x.length;
-    }
+    for (unsigned major = 0; major < var_data_num_rows.length; major++)
+      total_rows += var_data_num_rows[major];
 
     if (!delta_rows.resize (total_rows)) return false;
     /* init all rows to [0]*num_cols */
@@ -1998,7 +2157,7 @@
       /* deltas are stored in tuples(column based), convert them back into items
        * (row based) delta */
       const tuple_variations_t& tuples = vars[major];
-      unsigned num_rows = tuples.tuple_vars[0].deltas_x.length;
+      unsigned num_rows = var_data_num_rows[major];
       for (const tuple_delta_t& tuple: tuples.tuple_vars)
       {
         if (tuple.deltas_x.length != num_rows)
@@ -2180,12 +2339,12 @@
       /* just sanity check, this shouldn't happen */
       if (encoding.is_empty ())
         return false;
-  
+
       unsigned num_rows = encoding.items.length;
-  
+
       /* sort rows, make result deterministic */
       encoding.items.qsort (_cmp_row);
-  
+
       /* compile old to new var_idxes mapping */
       for (unsigned minor = 0; minor < num_rows; minor++)
       {
diff --git a/src/hb-ot-var-cvar-table.hh b/src/hb-ot-var-cvar-table.hh
index 381ae3c..3798ad3 100644
--- a/src/hb-ot-var-cvar-table.hh
+++ b/src/hb-ot-var-cvar-table.hh
@@ -45,7 +45,8 @@
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
-		  version.sanitize (c) && likely (version.major == 1) &&
+		  hb_barrier () &&
+		  likely (version.major == 1) &&
 		  tupleVariationData.sanitize (c));
   }
 
diff --git a/src/hb-ot-var-fvar-table.hh b/src/hb-ot-var-fvar-table.hh
index 4c4957b..2cd9afb 100644
--- a/src/hb-ot-var-fvar-table.hh
+++ b/src/hb-ot-var-fvar-table.hh
@@ -43,7 +43,7 @@
                                                     unsigned axis_index,
                                                     Triple axis_limit)
 {
-  float axis_coord = coords[axis_index].to_float ();
+  double axis_coord = static_cast<double>(coords[axis_index].to_float ());
   if (axis_limit.is_point ())
   {
     if (axis_limit.minimum != axis_coord)
@@ -131,6 +131,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
+		  hb_barrier () &&
 		  c->check_array (coordinatesZ.arrayZ, axis_count));
   }
 
@@ -232,7 +233,10 @@
   {
     float min, default_, max;
     get_coordinates (min, default_, max);
-    return TripleDistances (min, default_, max);
+    return TripleDistances (
+      static_cast<double>(min),
+      static_cast<double>(default_),
+      static_cast<double>(max));
   }
 
   bool subset (hb_subset_context_t *c) const
@@ -277,8 +281,10 @@
   {
     TRACE_SANITIZE (this);
     return_trace (version.sanitize (c) &&
+		  hb_barrier () &&
 		  likely (version.major == 1) &&
 		  c->check_struct (this) &&
+		  hb_barrier () &&
 		  axisSize == 20 && /* Assumed in our code. */
 		  instanceSize >= axisCount * 4 + 4 &&
 		  get_axes ().sanitize (c) &&
diff --git a/src/hb-ot-var-gvar-table.hh b/src/hb-ot-var-gvar-table.hh
index 8ef9f0e..d713084 100644
--- a/src/hb-ot-var-gvar-table.hh
+++ b/src/hb-ot-var-gvar-table.hh
@@ -101,10 +101,14 @@
         continue;
       }
 
+      bool is_composite_glyph = false;
+      is_composite_glyph = plan->composite_new_gids.has (new_gid);
+
       if (!p->decompile_tuple_variations (all_contour_points->length, true /* is_gvar */,
                                           iterator, &(plan->axes_old_index_tag_map),
                                           shared_indices, shared_tuples,
-                                          tuple_vars /* OUT */))
+                                          tuple_vars, /* OUT */
+                                          is_composite_glyph))
         return false;
       glyph_variations.push (std::move (tuple_vars));
     }
@@ -114,13 +118,15 @@
   bool instantiate (const hb_subset_plan_t *plan)
   {
     unsigned count = plan->new_to_old_gid_list.length;
+    bool iup_optimize = false;
+    iup_optimize = plan->flags & HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS;
     for (unsigned i = 0; i < count; i++)
     {
       hb_codepoint_t new_gid = plan->new_to_old_gid_list[i].first;
       contour_point_vector_t *all_points;
       if (!plan->new_gid_contour_points_map.has (new_gid, &all_points))
         return false;
-      if (!glyph_variations[i].instantiate (plan->axes_location, plan->axes_triple_distances, all_points))
+      if (!glyph_variations[i].instantiate (plan->axes_location, plan->axes_triple_distances, all_points, iup_optimize))
         return false;
     }
     return true;
@@ -296,7 +302,9 @@
   bool sanitize_shallow (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && (version.major == 1) &&
+    return_trace (c->check_struct (this) &&
+		  hb_barrier () &&
+		  (version.major == 1) &&
 		  sharedTuples.sanitize (c, this, axisCount * sharedTupleCount) &&
 		  (is_long_offset () ?
 		     c->check_array (get_long_offset_array (), c->get_num_glyphs () + 1) :
@@ -338,7 +346,8 @@
                   const glyph_variations_t& glyph_vars,
                   Iterator it,
                   unsigned axis_count,
-                  unsigned num_glyphs) const
+                  unsigned num_glyphs,
+                  bool force_long_offsets) const
   {
     TRACE_SERIALIZE (this);
     gvar *out = c->allocate_min<gvar> ();
@@ -350,7 +359,7 @@
     out->glyphCountX = hb_min (0xFFFFu, num_glyphs);
 
     unsigned glyph_var_data_size = glyph_vars.compiled_byte_size ();
-    bool long_offset = glyph_var_data_size & ~0xFFFFu;
+    bool long_offset = glyph_var_data_size & ~0xFFFFu || force_long_offsets;
     out->flags = long_offset ? 1 : 0;
 
     HBUINT8 *glyph_var_data_offsets = c->allocate_size<HBUINT8> ((long_offset ? 4 : 2) * (num_glyphs + 1), false);
@@ -391,7 +400,12 @@
     unsigned axis_count = c->plan->axes_index_map.get_population ();
     unsigned num_glyphs = c->plan->num_output_glyphs ();
     auto it = hb_iter (c->plan->new_to_old_gid_list);
-    return_trace (serialize (c->serializer, glyph_vars, it, axis_count, num_glyphs));
+
+    bool force_long_offsets = false;
+#ifdef HB_EXPERIMENTAL_API
+    force_long_offsets = c->plan->flags & HB_SUBSET_FLAGS_IFTB_REQUIREMENTS;
+#endif
+    return_trace (serialize (c->serializer, glyph_vars, it, axis_count, num_glyphs, force_long_offsets));
   }
 
   bool subset (hb_subset_context_t *c) const
@@ -426,7 +440,10 @@
       subset_data_size += get_glyph_var_data_bytes (c->source_blob, glyph_count, old_gid).length;
     }
 
-    bool long_offset = subset_data_size & ~0xFFFFu;
+    bool long_offset = (subset_data_size & ~0xFFFFu);
+#ifdef HB_EXPERIMENTAL_API
+    long_offset = long_offset || (c->plan->flags & HB_SUBSET_FLAGS_IFTB_REQUIREMENTS);
+#endif
     out->flags = long_offset ? 1 : 0;
 
     HBUINT8 *subset_offsets = c->serializer->allocate_size<HBUINT8> ((long_offset ? 4 : 2) * (num_glyphs + 1), false);
@@ -444,6 +461,8 @@
       hb_memcpy (tuples, this+sharedTuples, shared_tuple_size);
     }
 
+    /* This ordering relative to the shared tuples array, which puts the glyphVariationData
+       last in the table, is required when HB_SUBSET_FLAGS_IFTB_REQUIREMENTS is set */
     char *subset_data = c->serializer->allocate_size<char> (subset_data_size, false);
     if (!subset_data) return_trace (false);
     out->dataZ = subset_data - (char *) out;
diff --git a/src/hb-ot-var-hvar-table.hh b/src/hb-ot-var-hvar-table.hh
index ca1ea1c..33a4e1a 100644
--- a/src/hb-ot-var-hvar-table.hh
+++ b/src/hb-ot-var-hvar-table.hh
@@ -188,7 +188,7 @@
   ~hvarvvar_subset_plan_t() { fini (); }
 
   void init (const hb_array_t<const DeltaSetIndexMap *> &index_maps,
-	     const VariationStore &_var_store,
+	     const ItemVariationStore &_var_store,
 	     const hb_subset_plan_t *plan)
   {
     index_map_plans.resize (index_maps.length);
@@ -263,7 +263,7 @@
   hb_inc_bimap_t outer_map;
   hb_vector_t<hb_inc_bimap_t> inner_maps;
   hb_vector_t<index_map_subset_plan_t> index_map_plans;
-  const VariationStore *var_store;
+  const ItemVariationStore *var_store;
 
   protected:
   hb_vector_t<hb_set_t *> inner_sets;
@@ -288,6 +288,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (version.sanitize (c) &&
+		  hb_barrier () &&
 		  likely (version.major == 1) &&
 		  varStore.sanitize (c, this) &&
 		  advMap.sanitize (c, this) &&
@@ -295,7 +296,7 @@
 		  rsbMap.sanitize (c, this));
   }
 
-  const VariationStore& get_var_store () const
+  const ItemVariationStore& get_var_store () const
   { return this+varStore; }
 
   void listup_index_maps (hb_vector_t<const DeltaSetIndexMap *> &index_maps) const
@@ -383,7 +384,7 @@
 
   float get_advance_delta_unscaled (hb_codepoint_t  glyph,
 				    const int *coords, unsigned int coord_count,
-				    VariationStore::cache_t *store_cache = nullptr) const
+				    ItemVariationStore::cache_t *store_cache = nullptr) const
   {
     uint32_t varidx = (this+advMap).map (glyph);
     return (this+varStore).get_delta (varidx,
@@ -404,7 +405,7 @@
   public:
   FixedVersion<>version;	/* Version of the metrics variation table
 				 * initially set to 0x00010000u */
-  Offset32To<VariationStore>
+  Offset32To<ItemVariationStore>
 		varStore;	/* Offset to item variation store table. */
   Offset32To<DeltaSetIndexMap>
 		advMap;		/* Offset to advance var-idx mapping. */
diff --git a/src/hb-ot-var-mvar-table.hh b/src/hb-ot-var-mvar-table.hh
index ceabc9a..1f0401d 100644
--- a/src/hb-ot-var-mvar-table.hh
+++ b/src/hb-ot-var-mvar-table.hh
@@ -56,7 +56,7 @@
 
   public:
   Tag		valueTag;	/* Four-byte tag identifying a font-wide measure. */
-  VarIdx	varIdx;		/* Outer/inner index into VariationStore item. */
+  VarIdx	varIdx;		/* Outer/inner index into ItemVariationStore item. */
 
   public:
   DEFINE_SIZE_STATIC (8);
@@ -77,8 +77,10 @@
   {
     TRACE_SANITIZE (this);
     return_trace (version.sanitize (c) &&
+		  hb_barrier () &&
 		  likely (version.major == 1) &&
 		  c->check_struct (this) &&
+		  hb_barrier () &&
 		  valueRecordSize >= VariationValueRecord::static_size &&
 		  varStore.sanitize (c, this) &&
 		  c->check_range (valuesZ.arrayZ,
@@ -104,7 +106,7 @@
     out->valueRecordCount = valueRecordCount;
 
     item_variations_t item_vars;
-    const VariationStore& src_var_store = this+varStore;
+    const ItemVariationStore& src_var_store = this+varStore;
 
     if (!item_vars.instantiate (src_var_store, c->plan))
       return_trace (false);
@@ -157,7 +159,7 @@
   HBUINT16	valueRecordSize;/* The size in bytes of each value record —
 				 * must be greater than zero. */
   HBUINT16	valueRecordCount;/* The number of value records — may be zero. */
-  Offset16To<VariationStore>
+  Offset16To<ItemVariationStore>
 		varStore;	/* Offset to item variation store table. */
   UnsizedArrayOf<HBUINT8>
 		valuesZ;	/* Array of value records. The records must be
diff --git a/src/hb-ot-vorg-table.hh b/src/hb-ot-vorg-table.hh
index 671b6d2..95ae8ef 100644
--- a/src/hb-ot-vorg-table.hh
+++ b/src/hb-ot-vorg-table.hh
@@ -117,6 +117,7 @@
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
+		  hb_barrier () &&
 		  version.major == 1 &&
 		  vertYOrigins.sanitize (c));
   }
diff --git a/src/hb-priority-queue.hh b/src/hb-priority-queue.hh
index 2c8ccbf..274d5df 100644
--- a/src/hb-priority-queue.hh
+++ b/src/hb-priority-queue.hh
@@ -55,6 +55,9 @@
 
   bool in_error () const { return heap.in_error (); }
 
+  bool alloc (unsigned size)
+  { return heap.alloc (size); }
+
 #ifndef HB_OPTIMIZE_SIZE
   HB_ALWAYS_INLINE
 #endif
@@ -160,7 +163,7 @@
     goto repeat;
   }
 
-  void swap (unsigned a, unsigned b)
+  void swap (unsigned a, unsigned b) noexcept
   {
     assert (a < heap.length);
     assert (b < heap.length);
diff --git a/src/hb-repacker.hh b/src/hb-repacker.hh
index e9cd376..cb4fdee 100644
--- a/src/hb-repacker.hh
+++ b/src/hb-repacker.hh
@@ -239,6 +239,54 @@
 }
 
 static inline
+bool _resolve_shared_overflow(const hb_vector_t<graph::overflow_record_t>& overflows,
+                              int overflow_index,
+                              graph_t& sorted_graph)
+{
+  const graph::overflow_record_t& r = overflows[overflow_index];
+
+  // Find all of the parents in overflowing links that link to this
+  // same child node. We will then try duplicating the child node and
+  // re-assigning all of these parents to the duplicate.
+  hb_set_t parents;
+  parents.add(r.parent);
+  for (int i = overflow_index - 1; i >= 0; i--) {
+    const graph::overflow_record_t& r2 = overflows[i];
+    if (r2.child == r.child) {
+      parents.add(r2.parent);
+    }
+  }
+
+  unsigned result = sorted_graph.duplicate(&parents, r.child);
+  if (result == (unsigned) -1 && parents.get_population() > 2) {
+    // All links to the child are overflowing, so we can't include all
+    // in the duplication. Remove one parent from the duplication.
+    // Remove the lowest index parent, which will be the closest to the child.
+    parents.del(parents.get_min());
+    result = sorted_graph.duplicate(&parents, r.child);
+  }
+
+  if (result == (unsigned) -1) return result;
+
+  if (parents.get_population() > 1) {
+    // If the duplicated node has more than one parent pre-emptively raise it's priority to the maximum.
+    // This will place it close to the parents. Node's with only one parent, don't need this as normal overflow
+    // resolution will raise priority if needed.
+    //
+    // Reasoning: most of the parents to this child are likely at the same layer in the graph. Duplicating
+    // the child will theoretically allow it to be placed closer to it's parents. However, due to the shortest
+    // distance sort by default it's placement will remain in the same layer, thus it will remain in roughly the
+    // same position (and distance from parents) as the original child node. The overflow resolution will attempt
+    // to move nodes closer, but only for non-shared nodes. Since this node is shared, it will simply be given
+    // further duplication which defeats the attempt to duplicate with multiple parents. To fix this we
+    // pre-emptively raise priority now which allows the duplicated node to pack into the same layer as it's parents.
+    sorted_graph.vertices_[result].give_max_priority();
+  }
+
+  return result;
+}
+
+static inline
 bool _process_overflows (const hb_vector_t<graph::overflow_record_t>& overflows,
                          hb_set_t& priority_bumped_parents,
                          graph_t& sorted_graph)
@@ -254,7 +302,7 @@
     {
       // The child object is shared, we may be able to eliminate the overflow
       // by duplicating it.
-      if (sorted_graph.duplicate (r.parent, r.child) == (unsigned) -1) continue;
+      if (!_resolve_shared_overflow(overflows, i, sorted_graph)) continue;
       return true;
     }
 
@@ -289,9 +337,10 @@
 inline bool
 hb_resolve_graph_overflows (hb_tag_t table_tag,
                             unsigned max_rounds ,
-                            bool recalculate_extensions,
+                            bool always_recalculate_extensions,
                             graph_t& sorted_graph /* IN/OUT */)
 {
+  DEBUG_MSG (SUBSET_REPACK, nullptr, "Repacking %c%c%c%c.", HB_UNTAG(table_tag));
   sorted_graph.sort_shortest_distance ();
   if (sorted_graph.in_error ())
   {
@@ -303,12 +352,12 @@
   if (!will_overflow)
     return true;
 
+  bool is_gsub_or_gpos = (table_tag == HB_OT_TAG_GPOS ||  table_tag == HB_OT_TAG_GSUB);
   graph::gsubgpos_graph_context_t ext_context (table_tag, sorted_graph);
-  if ((table_tag == HB_OT_TAG_GPOS
-       ||  table_tag == HB_OT_TAG_GSUB)
-      && will_overflow)
+  if (is_gsub_or_gpos && will_overflow)
   {
-    if (recalculate_extensions)
+    DEBUG_MSG (SUBSET_REPACK, nullptr, "Applying GSUB/GPOS repacking specializations.");
+    if (always_recalculate_extensions)
     {
       DEBUG_MSG (SUBSET_REPACK, nullptr, "Splitting subtables if needed.");
       if (!_presplit_subtables_if_needed (ext_context)) {
@@ -364,6 +413,13 @@
 
   if (graph::will_overflow (sorted_graph))
   {
+    if (is_gsub_or_gpos && !always_recalculate_extensions) {
+      // If this a GSUB/GPOS table and we didn't try to extension promotion and table splitting then
+      // as a last ditch effort, re-run the repacker with it enabled.
+      DEBUG_MSG (SUBSET_REPACK, nullptr, "Failed to find a resolution. Re-running with extension promotion and table splitting enabled.");
+      return hb_resolve_graph_overflows (table_tag, max_rounds, true, sorted_graph);
+    }
+
     DEBUG_MSG (SUBSET_REPACK, nullptr, "Offset overflow resolution failed.");
     return false;
   }
@@ -388,7 +444,7 @@
 inline hb_blob_t*
 hb_resolve_overflows (const T& packed,
                       hb_tag_t table_tag,
-                      unsigned max_rounds = 20,
+                      unsigned max_rounds = 32,
                       bool recalculate_extensions = false) {
   graph_t sorted_graph (packed);
   if (sorted_graph.in_error ())
diff --git a/src/hb-sanitize.hh b/src/hb-sanitize.hh
index f2b7da1..408649c 100644
--- a/src/hb-sanitize.hh
+++ b/src/hb-sanitize.hh
@@ -134,7 +134,10 @@
   const char *get_name () { return "SANITIZE"; }
   template <typename T, typename F>
   bool may_dispatch (const T *obj HB_UNUSED, const F *format)
-  { return format->sanitize (this); }
+  {
+    return format->sanitize (this) &&
+	   hb_barrier ();
+  }
   static return_t default_return_value () { return true; }
   static return_t no_dispatch_return_value () { return false; }
   bool stop_sublookup_iteration (const return_t r) const { return !r; }
diff --git a/src/hb-serialize.hh b/src/hb-serialize.hh
index 15eccb6..e988451 100644
--- a/src/hb-serialize.hh
+++ b/src/hb-serialize.hh
@@ -91,7 +91,27 @@
     }
 #endif
 
-    friend void swap (object_t& a, object_t& b)
+    bool add_virtual_link (objidx_t objidx)
+    {
+      if (!objidx)
+        return false;
+
+      auto& link = *virtual_links.push ();
+      if (virtual_links.in_error ())
+        return false;
+
+      link.objidx = objidx;
+      // Remaining fields were previously zero'd by push():
+      // link.width = 0;
+      // link.is_signed = 0;
+      // link.whence = 0;
+      // link.position = 0;
+      // link.bias = 0;
+
+      return true;
+    }
+
+    friend void swap (object_t& a, object_t& b) noexcept
     {
       hb_swap (a.head, b.head);
       hb_swap (a.tail, b.tail);
@@ -156,9 +176,9 @@
     object_t *next;
 
     auto all_links () const HB_AUTO_RETURN
-        (( hb_concat (this->real_links, this->virtual_links) ));
+        (( hb_concat (real_links, virtual_links) ));
     auto all_links_writer () HB_AUTO_RETURN
-        (( hb_concat (this->real_links.writer (), this->virtual_links.writer ()) ));
+        (( hb_concat (real_links.writer (), virtual_links.writer ()) ));           
   };
 
   struct snapshot_t
@@ -469,16 +489,40 @@
 
     assert (current);
 
-    auto& link = *current->virtual_links.push ();
-    if (current->virtual_links.in_error ())
+    if (!current->add_virtual_link(objidx))
       err (HB_SERIALIZE_ERROR_OTHER);
+  }
 
-    link.width = 0;
-    link.objidx = objidx;
-    link.is_signed = 0;
-    link.whence = 0;
-    link.position = 0;
-    link.bias = 0;
+  objidx_t last_added_child_index() const {
+    if (unlikely (in_error ())) return (objidx_t) -1;
+
+    assert (current);
+    if (!bool(current->real_links)) {
+      return (objidx_t) -1;
+    }
+
+    return current->real_links[current->real_links.length - 1].objidx;
+  }
+
+  // For the current object ensure that the sub-table bytes for child objidx are always placed
+  // after the subtable bytes for any other existing children. This only ensures that the
+  // repacker will not move the target subtable before the other children
+  // (by adding virtual links). It is up to the caller to ensure the initial serialization
+  // order is correct.
+  void repack_last(objidx_t objidx) {
+    if (unlikely (in_error ())) return;
+
+    if (!objidx)
+      return;
+
+    assert (current);
+    for (auto& l : current->real_links) {
+      if (l.objidx == objidx) {
+        continue;
+      }
+
+      packed[l.objidx]->add_virtual_link(objidx);
+    }
   }
 
   template <typename T>
diff --git a/src/hb-set-digest.hh b/src/hb-set-digest.hh
index 5681641..b718b94 100644
--- a/src/hb-set-digest.hh
+++ b/src/hb-set-digest.hh
@@ -82,7 +82,9 @@
 
   void init () { mask = 0; }
 
-  void add (const hb_set_digest_bits_pattern_t &o) { mask |= o.mask; }
+  static hb_set_digest_bits_pattern_t full () { hb_set_digest_bits_pattern_t d; d.mask = (mask_t) -1; return d; }
+
+  void union_ (const hb_set_digest_bits_pattern_t &o) { mask |= o.mask; }
 
   void add (hb_codepoint_t g) { mask |= mask_for (g); }
 
@@ -129,11 +131,14 @@
   bool may_have (hb_codepoint_t g) const
   { return mask & mask_for (g); }
 
+  bool operator [] (hb_codepoint_t g) const
+  { return may_have (g); }
+
   private:
 
   static mask_t mask_for (hb_codepoint_t g)
   { return ((mask_t) 1) << ((g >> shift) & (mask_bits - 1)); }
-  mask_t mask;
+  mask_t mask = 0;
 };
 
 template <typename head_t, typename tail_t>
@@ -145,10 +150,12 @@
     tail.init ();
   }
 
-  void add (const hb_set_digest_combiner_t &o)
+  static hb_set_digest_combiner_t full () { hb_set_digest_combiner_t d; d.head = head_t::full(); d.tail = tail_t::full (); return d; }
+
+  void union_ (const hb_set_digest_combiner_t &o)
   {
-    head.add (o.head);
-    tail.add (o.tail);
+    head.union_ (o.head);
+    tail.union_(o.tail);
   }
 
   void add (hb_codepoint_t g)
@@ -188,6 +195,9 @@
     return head.may_have (g) && tail.may_have (g);
   }
 
+  bool operator [] (hb_codepoint_t g) const
+  { return may_have (g); }
+
   private:
   head_t head;
   tail_t tail;
diff --git a/src/hb-set.hh b/src/hb-set.hh
index 7d1c941..f6013a4 100644
--- a/src/hb-set.hh
+++ b/src/hb-set.hh
@@ -35,6 +35,8 @@
 template <typename impl_t>
 struct hb_sparseset_t
 {
+  static constexpr bool realloc_move = true;
+
   hb_object_header_t header;
   impl_t s;
 
@@ -42,10 +44,10 @@
   ~hb_sparseset_t () { fini (); }
 
   hb_sparseset_t (const hb_sparseset_t& other) : hb_sparseset_t () { set (other); }
-  hb_sparseset_t (hb_sparseset_t&& other) : hb_sparseset_t () { s = std::move (other.s); }
+  hb_sparseset_t (hb_sparseset_t&& other)  noexcept : hb_sparseset_t () { s = std::move (other.s); }
   hb_sparseset_t& operator = (const hb_sparseset_t& other) { set (other); return *this; }
-  hb_sparseset_t& operator = (hb_sparseset_t&& other) { s = std::move (other.s); return *this; }
-  friend void swap (hb_sparseset_t& a, hb_sparseset_t& b) { hb_swap (a.s, b.s); }
+  hb_sparseset_t& operator = (hb_sparseset_t&& other)  noexcept { s = std::move (other.s); return *this; }
+  friend void swap (hb_sparseset_t& a, hb_sparseset_t& b)  noexcept { hb_swap (a.s, b.s); }
 
   hb_sparseset_t (std::initializer_list<hb_codepoint_t> lst) : hb_sparseset_t ()
   {
@@ -84,7 +86,7 @@
   uint32_t hash () const { return s.hash (); }
 
   void add (hb_codepoint_t g) { s.add (g); }
-  bool add_range (hb_codepoint_t a, hb_codepoint_t b) { return s.add_range (a, b); }
+  bool add_range (hb_codepoint_t first, hb_codepoint_t last) { return s.add_range (first, last); }
 
   template <typename T>
   void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
@@ -164,7 +166,7 @@
   ~hb_set_t () = default;
   hb_set_t () : sparseset () {};
   hb_set_t (const hb_set_t &o) : sparseset ((sparseset &) o) {};
-  hb_set_t (hb_set_t&& o) : sparseset (std::move ((sparseset &) o)) {}
+  hb_set_t (hb_set_t&& o)  noexcept : sparseset (std::move ((sparseset &) o)) {}
   hb_set_t& operator = (const hb_set_t&) = default;
   hb_set_t& operator = (hb_set_t&&) = default;
   hb_set_t (std::initializer_list<hb_codepoint_t> lst) : sparseset (lst) {}
diff --git a/src/hb-subset-cff-common.hh b/src/hb-subset-cff-common.hh
index 462e99c..4039f9c 100644
--- a/src/hb-subset-cff-common.hh
+++ b/src/hb-subset-cff-common.hh
@@ -115,7 +115,7 @@
       encode_byte (OpCode_BCD);
 
       // Based on:
-      // https://github.com/fonttools/fonttools/blob/97ed3a61cde03e17b8be36f866192fbd56f1d1a7/Lib/fontTools/misc/psCharStrings.py#L265-L294
+      // https://github.com/fonttools/fonttools/blob/0738c41dfbcbc213ab9263f486ef0cccc6eb5ce5/Lib/fontTools/misc/psCharStrings.py#L267-L316
 
       char buf[16];
       /* FontTools has the following comment:
@@ -133,6 +133,10 @@
       (void) hb_uselocale (((void) freelocale (clocale), oldlocale));
 
       char *s = buf;
+      size_t len;
+      char *comma = strchr (s, ',');
+      if (comma) // Comma for some European locales in case no uselocale available.
+	*comma = '.';
       if (s[0] == '0' && s[1] == '.')
 	s++;
       else if (s[0] == '-' && s[1] == '0' && s[2] == '.')
@@ -140,6 +144,45 @@
 	s[1] = '-';
 	s++;
       }
+      else if ((len = strlen (s)) > 3 && !strcmp (s + len - 3, "000"))
+      {
+	unsigned exponent = len - 3;
+	char *s2 = s + exponent - 1;
+	while (*s2 == '0' && exponent > 1)
+	{
+	  s2--;
+	  exponent++;
+	}
+	snprintf (s2 + 1, sizeof (buf) - (s2 + 1 - buf), "E%u", exponent);
+      }
+      else
+      {
+	char *dot = strchr (s, '.');
+	char *e = strchr (s, 'E');
+	if (dot && e)
+	{
+	  memmove (dot, dot + 1, e - (dot + 1));
+	  int exponent = atoi (e + 1);
+	  int new_exponent = exponent - (e - (dot + 1));
+	  if (new_exponent == 1)
+	  {
+	    e[-1] = '0';
+	    e[0] = '\0';
+	  }
+	  else
+	    snprintf (e - 1, sizeof (buf) - (e - 1 - buf), "E%d", new_exponent);
+	}
+      }
+      if ((s[0] == '.' && s[1] == '0') || (s[0] == '-' && s[1] == '.' && s[2] == '0'))
+      {
+	int sign = s[0] == '-';
+	char *s2 = s + sign + 1;
+	while (*s2 == '0')
+	  s2++;
+	len = strlen (s2);
+	memmove (s + sign, s2, len);
+	snprintf (s + sign + len, sizeof (buf) - (s + sign + len - buf), "E-%u", (unsigned) (strlen (s + sign) - 1));
+      }
       hb_vector_t<char> nibbles;
       while (*s)
       {
@@ -155,20 +198,22 @@
 	    {
 	      s++;
 	      nibbles.push (0x0C); // E-
-	      continue;
+	    } else {
+	      if (c2 == '+')
+		s++;
+	      nibbles.push (0x0B); // E
 	    }
-	    if (c2 == '+')
+	    if (*s == '0')
 	      s++;
-	    nibbles.push (0x0B); // E
 	    continue;
 	  }
 
-	  case '.': case ',': // Comma for some European locales in case no uselocale available.
+	  case '.':
 	    nibbles.push (0x0A); // .
 	    continue;
 
 	  case '-':
-	    nibbles.push (0x0E); // .
+	    nibbles.push (0x0E); // -
 	    continue;
 	}
 
diff --git a/src/hb-subset-cff1.cc b/src/hb-subset-cff1.cc
index 872cba6..e9dd5d6 100644
--- a/src/hb-subset-cff1.cc
+++ b/src/hb-subset-cff1.cc
@@ -620,6 +620,12 @@
     drop_hints = plan->flags & HB_SUBSET_FLAGS_NO_HINTING;
     desubroutinize = plan->flags & HB_SUBSET_FLAGS_DESUBROUTINIZE;
 
+ #ifdef HB_EXPERIMENTAL_API
+    min_charstrings_off_size = (plan->flags & HB_SUBSET_FLAGS_IFTB_REQUIREMENTS) ? 4 : 0;
+ #else
+    min_charstrings_off_size = 0;
+ #endif
+
     subset_charset = !acc.is_predef_charset ();
     if (!subset_charset)
       /* check whether the subset renumbers any glyph IDs */
@@ -778,13 +784,43 @@
   unsigned int	topDictModSIDs[name_dict_values_t::ValCount];
 
   bool		desubroutinize = false;
+
+  unsigned	min_charstrings_off_size = 0;
 };
 } // namespace OT
 
+static bool _serialize_cff1_charstrings (hb_serialize_context_t *c,
+                                         struct OT::cff1_subset_plan &plan,
+                                         const OT::cff1::accelerator_subset_t  &acc)
+{
+  c->push<CFF1CharStrings> ();
+
+  unsigned data_size = 0;
+  unsigned total_size = CFF1CharStrings::total_size (plan.subset_charstrings, &data_size, plan.min_charstrings_off_size);
+  if (unlikely (!c->start_zerocopy (total_size)))
+    return false;
+
+  auto *cs = c->start_embed<CFF1CharStrings> ();
+  if (unlikely (!cs->serialize (c, plan.subset_charstrings, &data_size, plan.min_charstrings_off_size))) {
+    c->pop_discard ();
+    return false;
+  }
+
+  plan.info.char_strings_link = c->pop_pack (false);
+  return true;
+}
+
 bool
 OT::cff1::accelerator_subset_t::serialize (hb_serialize_context_t *c,
 					   struct OT::cff1_subset_plan &plan) const
 {
+  /* push charstrings onto the object stack first which will ensure it packs as the last
+     object in the table. Keeping the chastrings last satisfies the requirements for patching
+     via IFTB. If this ordering needs to be changed in the future, charstrings should be left
+     at the end whenever HB_SUBSET_FLAGS_ITFB_REQUIREMENTS is enabled. */
+  if (!_serialize_cff1_charstrings(c, plan, *this))
+    return false;
+
   /* private dicts & local subrs */
   for (int i = (int) privateDicts.length; --i >= 0 ;)
   {
@@ -823,25 +859,6 @@
   if (!is_CID ())
     plan.info.privateDictInfo = plan.fontdicts_mod[0].privateDictInfo;
 
-  /* CharStrings */
-  {
-    c->push<CFF1CharStrings> ();
-
-    unsigned data_size = 0;
-    unsigned total_size = CFF1CharStrings::total_size (plan.subset_charstrings, &data_size);
-    if (unlikely (!c->start_zerocopy (total_size)))
-       return false;
-
-    auto *cs = c->start_embed<CFF1CharStrings> ();
-    if (likely (cs->serialize (c, plan.subset_charstrings, &data_size)))
-      plan.info.char_strings_link = c->pop_pack (false);
-    else
-    {
-      c->pop_discard ();
-      return false;
-    }
-  }
-
   /* FDArray (FD Index) */
   if (fdArray != &Null (CFF1FDArray))
   {
diff --git a/src/hb-subset-cff2.cc b/src/hb-subset-cff2.cc
index 3c52fb9..9c9117d 100644
--- a/src/hb-subset-cff2.cc
+++ b/src/hb-subset-cff2.cc
@@ -248,7 +248,7 @@
 struct cff2_private_blend_encoder_param_t
 {
   cff2_private_blend_encoder_param_t (hb_serialize_context_t *c,
-				      const CFF2VariationStore *varStore,
+				      const CFF2ItemVariationStore *varStore,
 				      hb_array_t<int> normalized_coords) :
     c (c), varStore (varStore), normalized_coords (normalized_coords) {}
 
@@ -284,7 +284,7 @@
   unsigned ivs = 0;
   unsigned region_count = 0;
   hb_vector_t<float> scalars;
-  const	 CFF2VariationStore *varStore = nullptr;
+  const	 CFF2ItemVariationStore *varStore = nullptr;
   hb_array_t<int> normalized_coords;
 };
 
@@ -378,7 +378,7 @@
 struct cff2_private_dict_op_serializer_t : op_serializer_t
 {
   cff2_private_dict_op_serializer_t (bool desubroutinize_, bool drop_hints_, bool pinned_,
-				     const CFF::CFF2VariationStore* varStore_,
+				     const CFF::CFF2ItemVariationStore* varStore_,
 				     hb_array_t<int> normalized_coords_)
     : desubroutinize (desubroutinize_), drop_hints (drop_hints_), pinned (pinned_),
       varStore (varStore_), normalized_coords (normalized_coords_) {}
@@ -416,7 +416,7 @@
   const bool desubroutinize;
   const bool drop_hints;
   const bool pinned;
-  const CFF::CFF2VariationStore* varStore;
+  const CFF::CFF2ItemVariationStore* varStore;
   hb_array_t<int> normalized_coords;
 };
 
@@ -439,6 +439,12 @@
     desubroutinize = plan->flags & HB_SUBSET_FLAGS_DESUBROUTINIZE ||
 		     pinned; // For instancing we need this path
 
+ #ifdef HB_EXPERIMENTAL_API
+    min_charstrings_off_size = (plan->flags & HB_SUBSET_FLAGS_IFTB_REQUIREMENTS) ? 4 : 0;
+ #else
+    min_charstrings_off_size = 0;
+ #endif
+
     if (desubroutinize)
     {
       /* Flatten global & local subrs */
@@ -510,14 +516,45 @@
 
   bool	    drop_hints = false;
   bool	    desubroutinize = false;
+
+  unsigned  min_charstrings_off_size = 0;
 };
 } // namespace OT
 
+static bool _serialize_cff2_charstrings (hb_serialize_context_t *c,
+			     cff2_subset_plan &plan,
+			     const OT::cff2::accelerator_subset_t  &acc)
+{
+  c->push ();
+
+  unsigned data_size = 0;
+  unsigned total_size = CFF2CharStrings::total_size (plan.subset_charstrings, &data_size, plan.min_charstrings_off_size);
+  if (unlikely (!c->start_zerocopy (total_size)))
+    return false;
+
+  auto *cs = c->start_embed<CFF2CharStrings> ();
+  if (unlikely (!cs->serialize (c, plan.subset_charstrings, &data_size, plan.min_charstrings_off_size)))
+  {
+    c->pop_discard ();
+    return false;
+  }
+
+  plan.info.char_strings_link = c->pop_pack (false);
+  return true;
+}
+
 bool
 OT::cff2::accelerator_subset_t::serialize (hb_serialize_context_t *c,
 					   struct cff2_subset_plan &plan,
 					   hb_array_t<int> normalized_coords) const
 {
+  /* push charstrings onto the object stack first which will ensure it packs as the last
+     object in the table. Keeping the chastrings last satisfies the requirements for patching
+     via IFTB. If this ordering needs to be changed in the future, charstrings should be left
+     at the end whenever HB_SUBSET_FLAGS_ITFB_REQUIREMENTS is enabled. */
+  if (!_serialize_cff2_charstrings(c, plan, *this))
+    return false;
+
   /* private dicts & local subrs */
   hb_vector_t<table_info_t>  private_dict_infos;
   if (unlikely (!private_dict_infos.resize (plan.subset_fdcount))) return false;
@@ -556,25 +593,6 @@
     }
   }
 
-  /* CharStrings */
-  {
-    c->push ();
-
-    unsigned data_size = 0;
-    unsigned total_size = CFF2CharStrings::total_size (plan.subset_charstrings, &data_size);
-    if (unlikely (!c->start_zerocopy (total_size)))
-       return false;
-
-    auto *cs = c->start_embed<CFF2CharStrings> ();
-    if (likely (cs->serialize (c, plan.subset_charstrings, &data_size)))
-      plan.info.char_strings_link = c->pop_pack (false);
-    else
-    {
-      c->pop_discard ();
-      return false;
-    }
-  }
-
   /* FDSelect */
   if (fdSelect != &Null (CFF2FDSelect))
   {
@@ -610,10 +628,10 @@
   }
 
   /* variation store */
-  if (varStore != &Null (CFF2VariationStore) &&
+  if (varStore != &Null (CFF2ItemVariationStore) &&
       !plan.pinned)
   {
-    auto *dest = c->push<CFF2VariationStore> ();
+    auto *dest = c->push<CFF2ItemVariationStore> ();
     if (unlikely (!dest->serialize (c, varStore)))
     {
       c->pop_discard ();
@@ -648,6 +666,9 @@
 bool
 OT::cff2::accelerator_subset_t::subset (hb_subset_context_t *c) const
 {
+  if (c->plan->normalized_coords && !c->plan->all_axes_pinned)
+    fprintf (stdout, "warning: CFF partial instancing is not supported.\n");
+
   cff2_subset_plan cff2_plan;
 
   if (unlikely (!cff2_plan.create (*this, c->plan))) return false;
diff --git a/src/hb-subset-input.cc b/src/hb-subset-input.cc
index 0277d3d..8974755 100644
--- a/src/hb-subset-input.cc
+++ b/src/hb-subset-input.cc
@@ -24,6 +24,7 @@
  * Google Author(s): Garret Rieger, Rod Sheeter, Behdad Esfahbod
  */
 
+#include "hb-subset-instancer-solver.hh"
 #include "hb-subset.hh"
 #include "hb-set.hh"
 #include "hb-utf.hh"
@@ -50,7 +51,6 @@
     HB_TAG ('k', 'e', 'r', 'n'),
 
     // Copied from fontTools:
-    HB_TAG ('B', 'A', 'S', 'E'),
     HB_TAG ('J', 'S', 'T', 'F'),
     HB_TAG ('D', 'S', 'I', 'G'),
     HB_TAG ('E', 'B', 'D', 'T'),
@@ -123,6 +123,12 @@
     //justify
     HB_TAG ('j', 'a', 'l', 't'), // HarfBuzz doesn't use; others might
 
+    //East Asian spacing
+    HB_TAG ('c', 'h', 'w', 's'),
+    HB_TAG ('v', 'c', 'h', 'w'),
+    HB_TAG ('h', 'a', 'l', 't'),
+    HB_TAG ('v', 'h', 'a', 'l'),
+
     //private
     HB_TAG ('H', 'a', 'r', 'f'),
     HB_TAG ('H', 'A', 'R', 'F'),
@@ -412,6 +418,46 @@
 
 #ifndef HB_NO_VAR
 /**
+ * hb_subset_input_pin_all_axes_to_default: (skip)
+ * @input: a #hb_subset_input_t object.
+ * @face: a #hb_face_t object.
+ *
+ * Pin all axes to default locations in the given subset input object.
+ *
+ * All axes in a font must be pinned. Additionally, `CFF2` table, if present,
+ * will be de-subroutinized.
+ *
+ * Return value: `true` if success, `false` otherwise
+ *
+ * Since: 8.3.1
+ **/
+HB_EXTERN hb_bool_t
+hb_subset_input_pin_all_axes_to_default (hb_subset_input_t  *input,
+                                         hb_face_t          *face)
+{
+  unsigned axis_count = hb_ot_var_get_axis_count (face);
+  if (!axis_count) return false;
+
+  hb_ot_var_axis_info_t *axis_infos = (hb_ot_var_axis_info_t *) hb_calloc (axis_count, sizeof (hb_ot_var_axis_info_t));
+  if (unlikely (!axis_infos)) return false;
+
+  (void) hb_ot_var_get_axis_infos (face, 0, &axis_count, axis_infos);
+
+  for (unsigned i = 0; i < axis_count; i++)
+  {
+    hb_tag_t axis_tag = axis_infos[i].tag;
+    double default_val = (double) axis_infos[i].default_value;
+    if (!input->axes_location.set (axis_tag, Triple (default_val, default_val, default_val)))
+    {
+      hb_free (axis_infos);
+      return false;
+    }
+  }
+  hb_free (axis_infos);
+  return true;
+}
+
+/**
  * hb_subset_input_pin_axis_to_default: (skip)
  * @input: a #hb_subset_input_t object.
  * @face: a #hb_face_t object.
@@ -435,7 +481,7 @@
   if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info))
     return false;
 
-  float default_val = axis_info.default_value;
+  double default_val = (double) axis_info.default_value;
   return input->axes_location.set (axis_tag, Triple (default_val, default_val, default_val));
 }
 
@@ -465,26 +511,22 @@
   if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info))
     return false;
 
-  float val = hb_clamp(axis_value, axis_info.min_value, axis_info.max_value);
+  double val = hb_clamp((double) axis_value, (double) axis_info.min_value, (double) axis_info.max_value);
   return input->axes_location.set (axis_tag, Triple (val, val, val));
 }
 
-#ifdef HB_EXPERIMENTAL_API
 /**
  * hb_subset_input_set_axis_range: (skip)
  * @input: a #hb_subset_input_t object.
  * @face: a #hb_face_t object.
  * @axis_tag: Tag of the axis
- * @axis_min_value: Minimum value of the axis variation range to set
- * @axis_max_value: Maximum value of the axis variation range to set
- * @axis_def_value: Default value of the axis variation range to set, in case of
- * null, it'll be determined automatically
+ * @axis_min_value: Minimum value of the axis variation range to set, if NaN the existing min will be used.
+ * @axis_max_value: Maximum value of the axis variation range to set  if NaN the existing max will be used.
+ * @axis_def_value: Default value of the axis variation range to set, if NaN the existing default will be used.
  *
  * Restricting the range of variation on an axis in the given subset input object.
  * New min/default/max values will be clamped if they're not within the fvar axis range.
- * If the new default value is null:
- * If the fvar axis default value is within the new range, then new default
- * value is the same as original default value.
+ *
  * If the fvar axis default value is not within the new range, the new default
  * value will be changed to the new min or max value, whichever is closer to the fvar
  * axis default.
@@ -495,7 +537,7 @@
  *
  * Return value: `true` if success, `false` otherwise
  *
- * XSince: EXPERIMENTAL
+ * Since: 8.5.0
  **/
 HB_EXTERN hb_bool_t
 hb_subset_input_set_axis_range (hb_subset_input_t  *input,
@@ -503,22 +545,57 @@
                                 hb_tag_t            axis_tag,
                                 float               axis_min_value,
                                 float               axis_max_value,
-                                float              *axis_def_value /* IN, maybe NULL */)
+                                float               axis_def_value)
 {
-  if (axis_min_value > axis_max_value)
-    return false;
-
   hb_ot_var_axis_info_t axis_info;
   if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info))
     return false;
 
-  float new_min_val = hb_clamp(axis_min_value, axis_info.min_value, axis_info.max_value);
-  float new_max_val = hb_clamp(axis_max_value, axis_info.min_value, axis_info.max_value);
-  float new_default_val = axis_def_value ? *axis_def_value : axis_info.default_value;
-  new_default_val = hb_clamp(new_default_val, new_min_val, new_max_val);
-  return input->axes_location.set (axis_tag, Triple (new_min_val, new_default_val, new_max_val));
+  float min = !std::isnan(axis_min_value) ? axis_min_value : axis_info.min_value;
+  float max = !std::isnan(axis_max_value) ? axis_max_value : axis_info.max_value;
+  float def = !std::isnan(axis_def_value) ? axis_def_value : axis_info.default_value;
+
+  if (min > max)
+    return false;
+
+  float new_min_val = hb_clamp(min, axis_info.min_value, axis_info.max_value);
+  float new_max_val = hb_clamp(max, axis_info.min_value, axis_info.max_value);
+  float new_default_val = hb_clamp(def, new_min_val, new_max_val);
+  return input->axes_location.set (axis_tag, Triple ((double) new_min_val, (double) new_default_val, (double) new_max_val));
 }
-#endif
+
+/**
+ * hb_subset_input_get_axis_range: (skip)
+ * @input: a #hb_subset_input_t object.
+ * @axis_tag: Tag of the axis
+ * @axis_min_value: Set to the previously configured minimum value of the axis variation range.
+ * @axis_max_value: Set to the previously configured maximum value of the axis variation range.
+ * @axis_def_value: Set to the previously configured default value of the axis variation range.
+ *
+ * Gets the axis range assigned by previous calls to hb_subset_input_set_axis_range.
+ *
+ * Return value: `true` if a range has been set for this axis tag, `false` otherwise.
+ *
+ * Since: 8.5.0
+ **/
+HB_EXTERN hb_bool_t
+hb_subset_input_get_axis_range (hb_subset_input_t  *input,
+				hb_tag_t            axis_tag,
+				float              *axis_min_value,
+				float              *axis_max_value,
+				float              *axis_def_value)
+
+{
+  Triple* triple;
+  if (!input->axes_location.has(axis_tag, &triple)) {
+    return false;
+  }
+
+  *axis_min_value = triple->minimum;
+  *axis_def_value = triple->middle;
+  *axis_max_value = triple->maximum;
+  return true;
+}
 #endif
 
 /**
@@ -667,5 +744,4 @@
   input->name_table_overrides.set (hb_ot_name_record_ids_t (platform_id, encoding_id, language_id, name_id), name_bytes);
   return true;
 }
-
 #endif
diff --git a/src/hb-subset-instancer-iup.cc b/src/hb-subset-instancer-iup.cc
new file mode 100644
index 0000000..074657a
--- /dev/null
+++ b/src/hb-subset-instancer-iup.cc
@@ -0,0 +1,532 @@
+/*
+ * 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.
+ */
+
+#include "hb-subset-instancer-iup.hh"
+
+/* This file is a straight port of the following:
+ *
+ * https://github.com/fonttools/fonttools/blob/main/Lib/fontTools/varLib/iup.py
+ *
+ * Where that file returns optimzied deltas vector, we return optimized
+ * referenced point indices.
+ */
+
+constexpr static unsigned MAX_LOOKBACK = 8;
+
+static void _iup_contour_bound_forced_set (const hb_array_t<const contour_point_t> contour_points,
+                                           const hb_array_t<const int> x_deltas,
+                                           const hb_array_t<const int> y_deltas,
+                                           hb_set_t& forced_set, /* OUT */
+                                           double tolerance = 0.0)
+{
+  unsigned len = contour_points.length;
+  unsigned next_i = 0;
+  for (int i = len - 1; i >= 0; i--)
+  {
+    unsigned last_i = (len + i -1) % len;
+    for (unsigned j = 0; j < 2; j++)
+    {
+      double cj, lcj, ncj;
+      int dj, ldj, ndj;
+      if (j == 0)
+      {
+        cj = static_cast<double> (contour_points.arrayZ[i].x);
+        dj = x_deltas.arrayZ[i];
+        lcj = static_cast<double> (contour_points.arrayZ[last_i].x);
+        ldj = x_deltas.arrayZ[last_i];
+        ncj = static_cast<double> (contour_points.arrayZ[next_i].x);
+        ndj = x_deltas.arrayZ[next_i];
+      }
+      else
+      {
+        cj = static_cast<double> (contour_points.arrayZ[i].y);
+        dj = y_deltas.arrayZ[i];
+        lcj = static_cast<double> (contour_points.arrayZ[last_i].y);
+        ldj = y_deltas.arrayZ[last_i];
+        ncj = static_cast<double> (contour_points.arrayZ[next_i].y);
+        ndj = y_deltas.arrayZ[next_i];
+      }
+
+      double c1, c2;
+      int d1, d2;
+      if (lcj <= ncj)
+      {
+        c1 = lcj;
+        c2 = ncj;
+        d1 = ldj;
+        d2 = ndj;
+      }
+      else
+      {
+        c1 = ncj;
+        c2 = lcj;
+        d1 = ndj;
+        d2 = ldj;
+      }
+
+      bool force = false;
+      if (c1 == c2)
+      {
+        if (abs (d1 - d2) > tolerance && abs (dj) > tolerance)
+          force = true;
+      }
+      else if (c1 <= cj && cj <= c2)
+      {
+        if (!(hb_min (d1, d2) - tolerance <= dj &&
+              dj <= hb_max (d1, d2) + tolerance))
+          force = true;
+      }
+      else
+      {
+        if (d1 != d2)
+        {
+          if (cj < c1)
+          {
+            if (abs (dj) > tolerance &&
+                abs (dj - d1) > tolerance &&
+                ((dj - tolerance < d1) != (d1 < d2)))
+                force = true;
+          }
+          else
+          {
+            if (abs (dj) > tolerance &&
+                abs (dj - d2) > tolerance &&
+                ((d2 < dj + tolerance) != (d1 < d2)))
+              force = true;
+          }
+        }
+      }
+
+      if (force)
+      {
+        forced_set.add (i);
+        break;
+      }
+    }
+    next_i = i;
+  }
+}
+
+template <typename T,
+          hb_enable_if (hb_is_trivially_copyable (T))>
+static bool rotate_array (const hb_array_t<const T>& org_array,
+                          int k,
+                          hb_vector_t<T>& out)
+{
+  unsigned n = org_array.length;
+  if (!n) return true;
+  if (unlikely (!out.resize (n, false)))
+    return false;
+
+  unsigned item_size = hb_static_size (T);
+  if (k < 0)
+    k = n - (-k) % n;
+  else
+    k %= n;
+
+  hb_memcpy ((void *) out.arrayZ, (const void *) (org_array.arrayZ + n - k), k * item_size);
+  hb_memcpy ((void *) (out.arrayZ + k), (const void *) org_array.arrayZ, (n - k) * item_size);
+  return true;
+}
+
+static bool rotate_set (const hb_set_t& org_set,
+                        int k,
+                        unsigned n,
+                        hb_set_t& out)
+{
+  if (!n) return false;
+  k %= n;
+  if (k < 0)
+    k = n + k;
+
+  if (k == 0)
+  {
+    out.set (org_set);
+  }
+  else
+  {
+    for (auto v : org_set)
+      out.add ((v + k) % n);
+  }
+  return !out.in_error ();
+}
+
+/* Given two reference coordinates (start and end of contour_points array),
+ * output interpolated deltas for points in between */
+static bool _iup_segment (const hb_array_t<const contour_point_t> contour_points,
+                          const hb_array_t<const int> x_deltas,
+                          const hb_array_t<const int> y_deltas,
+                          const contour_point_t& p1, const contour_point_t& p2,
+                          int p1_dx, int p2_dx,
+                          int p1_dy, int p2_dy,
+                          hb_vector_t<double>& interp_x_deltas, /* OUT */
+                          hb_vector_t<double>& interp_y_deltas /* OUT */)
+{
+  unsigned n = contour_points.length;
+  if (unlikely (!interp_x_deltas.resize (n, false) ||
+                !interp_y_deltas.resize (n, false)))
+    return false;
+
+  for (unsigned j = 0; j < 2; j++)
+  {
+    double x1, x2, d1, d2;
+    double *out;
+    if (j == 0)
+    {
+      x1 = static_cast<double> (p1.x);
+      x2 = static_cast<double> (p2.x);
+      d1 = p1_dx;
+      d2 = p2_dx;
+      out = interp_x_deltas.arrayZ;
+    }
+    else
+    {
+      x1 = static_cast<double> (p1.y);
+      x2 = static_cast<double> (p2.y);
+      d1 = p1_dy;
+      d2 = p2_dy;
+      out = interp_y_deltas.arrayZ;
+    }
+
+    if (x1 == x2)
+    {
+      if (d1 == d2)
+      {
+        for (unsigned i = 0; i < n; i++)
+          out[i] = d1;
+      }
+      else
+      {
+        for (unsigned i = 0; i < n; i++)
+          out[i] = 0.0;
+      }
+      continue;
+    }
+
+    if (x1 > x2)
+    {
+      hb_swap (x1, x2);
+      hb_swap (d1, d2);
+    }
+
+    double scale = (d2 - d1) / (x2 - x1);
+    for (unsigned i = 0; i < n; i++)
+    {
+      double x = (j == 0 ? static_cast<double> (contour_points.arrayZ[i].x) : static_cast<double> (contour_points.arrayZ[i].y));
+      double d;
+      if (x <= x1)
+        d = d1;
+      else if (x >= x2)
+        d = d2;
+      else
+        d = d1 + (x - x1) * scale;
+
+      out[i] = d;
+    }
+  }
+  return true;
+}
+
+static bool _can_iup_in_between (const hb_array_t<const contour_point_t> contour_points,
+                                 const hb_array_t<const int> x_deltas,
+                                 const hb_array_t<const int> y_deltas,
+                                 const contour_point_t& p1, const contour_point_t& p2,
+                                 int p1_dx, int p2_dx,
+                                 int p1_dy, int p2_dy,
+                                 double tolerance)
+{
+  hb_vector_t<double> interp_x_deltas, interp_y_deltas;
+  if (!_iup_segment (contour_points, x_deltas, y_deltas,
+                     p1, p2, p1_dx, p2_dx, p1_dy, p2_dy,
+                     interp_x_deltas, interp_y_deltas))
+    return false;
+
+  unsigned num = contour_points.length;
+
+  for (unsigned i = 0; i < num; i++)
+  {
+    double dx = static_cast<double> (x_deltas.arrayZ[i]) - interp_x_deltas.arrayZ[i];
+    double dy = static_cast<double> (y_deltas.arrayZ[i]) - interp_y_deltas.arrayZ[i];
+  
+    if (sqrt (dx * dx + dy * dy) > tolerance)
+      return false;
+  }
+  return true;
+}
+
+static bool _iup_contour_optimize_dp (const contour_point_vector_t& contour_points,
+                                      const hb_vector_t<int>& x_deltas,
+                                      const hb_vector_t<int>& y_deltas,
+                                      const hb_set_t& forced_set,
+                                      double tolerance,
+                                      unsigned lookback,
+                                      hb_vector_t<unsigned>& costs, /* OUT */
+                                      hb_vector_t<int>& chain /* OUT */)
+{
+  unsigned n = contour_points.length;
+  if (unlikely (!costs.resize (n, false) ||
+                !chain.resize (n, false)))
+    return false;
+
+  lookback = hb_min (lookback, MAX_LOOKBACK);
+
+  for (unsigned i = 0; i < n; i++)
+  {
+    unsigned best_cost = (i == 0 ? 1 : costs.arrayZ[i-1] + 1);
+    
+    costs.arrayZ[i] = best_cost;
+    chain.arrayZ[i] = (i == 0 ? -1 : i - 1);
+
+    if (i > 0 && forced_set.has (i - 1))
+      continue;
+
+    int lookback_index = hb_max ((int) i - (int) lookback + 1, -1);
+    for (int j = i - 2; j >= lookback_index; j--)
+    {
+      unsigned cost = j == -1 ? 1 : costs.arrayZ[j] + 1;
+      /* num points between i and j */
+      unsigned num_points = i - j - 1;
+      unsigned p1 = (j == -1 ? n - 1 : j);
+      if (cost < best_cost &&
+          _can_iup_in_between (contour_points.as_array ().sub_array (j + 1, num_points),
+                               x_deltas.as_array ().sub_array (j + 1, num_points),
+                               y_deltas.as_array ().sub_array (j + 1, num_points),
+                               contour_points.arrayZ[p1], contour_points.arrayZ[i],
+                               x_deltas.arrayZ[p1], x_deltas.arrayZ[i],
+                               y_deltas.arrayZ[p1], y_deltas.arrayZ[i],
+                               tolerance))
+      {
+        best_cost = cost;
+        costs.arrayZ[i] = best_cost;
+        chain.arrayZ[i] = j;
+      }
+
+      if (j > 0 && forced_set.has (j))
+        break;
+    }
+  }
+  return true;
+}
+
+static bool _iup_contour_optimize (const hb_array_t<const contour_point_t> contour_points,
+                                   const hb_array_t<const int> x_deltas,
+                                   const hb_array_t<const int> y_deltas,
+                                   hb_array_t<bool> opt_indices, /* OUT */
+                                   double tolerance = 0.0)
+{
+  unsigned n = contour_points.length;
+  if (opt_indices.length != n ||
+      x_deltas.length != n ||
+      y_deltas.length != n)
+    return false;
+
+  bool all_within_tolerance = true;
+  for (unsigned i = 0; i < n; i++)
+  {
+    int dx = x_deltas.arrayZ[i];
+    int dy = y_deltas.arrayZ[i];
+    if (sqrt ((double) dx * dx + (double) dy * dy) > tolerance)
+    {
+      all_within_tolerance = false;
+      break;
+    }
+  }
+
+  /* If all are within tolerance distance, do nothing, opt_indices is
+   * initilized to false */
+  if (all_within_tolerance)
+    return true;
+
+  /* If there's exactly one point, return it */
+  if (n == 1)
+  {
+    opt_indices.arrayZ[0] = true;
+    return true;
+  }
+
+  /* If all deltas are exactly the same, return just one (the first one) */
+  bool all_deltas_are_equal = true;
+  for (unsigned i = 1; i < n; i++)
+    if (x_deltas.arrayZ[i] != x_deltas.arrayZ[0] ||
+        y_deltas.arrayZ[i] != y_deltas.arrayZ[0])
+    {
+      all_deltas_are_equal = false;
+      break;
+    }
+
+  if (all_deltas_are_equal)
+  {
+    opt_indices.arrayZ[0] = true;
+    return true;
+  }
+
+  /* else, solve the general problem using Dynamic Programming */
+  hb_set_t forced_set;
+  _iup_contour_bound_forced_set (contour_points, x_deltas, y_deltas, forced_set, tolerance);
+
+  if (!forced_set.is_empty ())
+  {
+    int k = n - 1 - forced_set.get_max ();
+    if (k < 0)
+      return false;
+
+    hb_vector_t<int> rot_x_deltas, rot_y_deltas;
+    contour_point_vector_t rot_points;
+    hb_set_t rot_forced_set;
+    if (!rotate_array (contour_points, k, rot_points) ||
+        !rotate_array (x_deltas, k, rot_x_deltas) ||
+        !rotate_array (y_deltas, k, rot_y_deltas) ||
+        !rotate_set (forced_set, k, n, rot_forced_set))
+      return false;
+
+    hb_vector_t<unsigned> costs;
+    hb_vector_t<int> chain;
+
+    if (!_iup_contour_optimize_dp (rot_points, rot_x_deltas, rot_y_deltas,
+                                   rot_forced_set, tolerance, n,
+                                   costs, chain))
+      return false;
+
+    hb_set_t solution;
+    int index = n - 1;
+    while (index != -1)
+    {
+      solution.add (index);
+      index = chain.arrayZ[index];
+    }
+
+    if (solution.is_empty () ||
+        forced_set.get_population () > solution.get_population ())
+      return false;
+
+    for (unsigned i : solution)
+      opt_indices.arrayZ[i] = true;
+
+    hb_vector_t<bool> rot_indices;
+    const hb_array_t<const bool> opt_indices_array (opt_indices.arrayZ, opt_indices.length);
+    rotate_array (opt_indices_array, -k, rot_indices);
+
+    for (unsigned i = 0; i < n; i++)
+      opt_indices.arrayZ[i] = rot_indices.arrayZ[i];
+  }
+  else
+  {
+    hb_vector_t<int> repeat_x_deltas, repeat_y_deltas;
+    contour_point_vector_t repeat_points;
+
+    if (unlikely (!repeat_x_deltas.resize (n * 2, false) ||
+                  !repeat_y_deltas.resize (n * 2, false) ||
+                  !repeat_points.resize (n * 2, false)))
+      return false;
+
+    unsigned contour_point_size = hb_static_size (contour_point_t);
+    for (unsigned i = 0; i < n; i++)
+    {
+      hb_memcpy ((void *) repeat_x_deltas.arrayZ, (const void *) x_deltas.arrayZ, n * sizeof (repeat_x_deltas[0]));
+      hb_memcpy ((void *) (repeat_x_deltas.arrayZ + n), (const void *) x_deltas.arrayZ, n * sizeof (repeat_x_deltas[0]));
+
+      hb_memcpy ((void *) repeat_y_deltas.arrayZ, (const void *) y_deltas.arrayZ, n * sizeof (repeat_x_deltas[0]));
+      hb_memcpy ((void *) (repeat_y_deltas.arrayZ + n), (const void *) y_deltas.arrayZ, n * sizeof (repeat_x_deltas[0]));
+
+      hb_memcpy ((void *) repeat_points.arrayZ, (const void *) contour_points.arrayZ, n * contour_point_size);
+      hb_memcpy ((void *) (repeat_points.arrayZ + n), (const void *) contour_points.arrayZ, n * contour_point_size);
+    }
+
+    hb_vector_t<unsigned> costs;
+    hb_vector_t<int> chain;
+    if (!_iup_contour_optimize_dp (repeat_points, repeat_x_deltas, repeat_y_deltas,
+                                   forced_set, tolerance, n,
+                                   costs, chain))
+      return false;
+
+    unsigned best_cost = n + 1;
+    int len = costs.length;
+    hb_set_t best_sol;
+    for (int start = n - 1; start < len; start++)
+    {
+      hb_set_t solution;
+      int i = start;
+      int lookback = start - (int) n;
+      while (i > lookback)
+      {
+        solution.add (i % n);
+        i = chain.arrayZ[i];
+      }
+      if (i == lookback)
+      {
+        unsigned cost_i = i < 0 ? 0 : costs.arrayZ[i];
+        unsigned cost = costs.arrayZ[start] - cost_i;
+        if (cost <= best_cost)
+        {
+          best_sol.set (solution);
+          best_cost = cost;
+        }
+      }
+    }
+
+    for (unsigned i = 0; i < n; i++)
+      if (best_sol.has (i))
+        opt_indices.arrayZ[i] = true;
+  }
+  return true;
+}
+
+bool iup_delta_optimize (const contour_point_vector_t& contour_points,
+                         const hb_vector_t<int>& x_deltas,
+                         const hb_vector_t<int>& y_deltas,
+                         hb_vector_t<bool>& opt_indices, /* OUT */
+                         double tolerance)
+{
+  if (!opt_indices.resize (contour_points.length))
+      return false;
+
+  hb_vector_t<unsigned> end_points;
+  unsigned count = contour_points.length;
+  if (unlikely (!end_points.alloc (count)))
+    return false;
+
+  for (unsigned i = 0; i < count - 4; i++)
+    if (contour_points.arrayZ[i].is_end_point)
+      end_points.push (i);
+
+  /* phantom points */
+  for (unsigned i = count - 4; i < count; i++)
+    end_points.push (i);
+
+  if (end_points.in_error ()) return false;
+
+  unsigned start = 0;
+  for (unsigned end : end_points)
+  {
+    unsigned len = end - start + 1;
+    if (!_iup_contour_optimize (contour_points.as_array ().sub_array (start, len),
+                                x_deltas.as_array ().sub_array (start, len),
+                                y_deltas.as_array ().sub_array (start, len),
+                                opt_indices.as_array ().sub_array (start, len),
+                                tolerance))
+      return false;
+    start = end + 1;
+  }
+  return true;
+}
diff --git a/src/hb-subset-instancer-iup.hh b/src/hb-subset-instancer-iup.hh
new file mode 100644
index 0000000..01987bd
--- /dev/null
+++ b/src/hb-subset-instancer-iup.hh
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+#ifndef HB_SUBSET_INSTANCER_IUP_HH
+#define HB_SUBSET_INSTANCER_IUP_HH
+
+#include "hb-subset-plan.hh"
+/* given contour points and deltas, optimize a set of referenced points within error
+ * tolerance. Returns optimized referenced point indices */
+HB_INTERNAL bool iup_delta_optimize (const contour_point_vector_t& contour_points,
+                                     const hb_vector_t<int>& x_deltas,
+                                     const hb_vector_t<int>& y_deltas,
+                                     hb_vector_t<bool>& opt_indices, /* OUT */
+                                     double tolerance = 0.0);
+
+#endif /* HB_SUBSET_INSTANCER_IUP_HH */
diff --git a/src/hb-subset-instancer-solver.cc b/src/hb-subset-instancer-solver.cc
index 4cb3f8a..ca903e2 100644
--- a/src/hb-subset-instancer-solver.cc
+++ b/src/hb-subset-instancer-solver.cc
@@ -32,17 +32,17 @@
  * This should be safe.
  */
 
-constexpr static float EPSILON = 1.f / (1 << 14);
-constexpr static float MAX_F2DOT14 = float (0x7FFF) / (1 << 14);
+constexpr static double EPSILON = 1.0 / (1 << 14);
+constexpr static double MAX_F2DOT14 = double (0x7FFF) / (1 << 14);
 
 static inline Triple _reverse_negate(const Triple &v)
 { return {-v.maximum, -v.middle, -v.minimum}; }
 
 
-static inline float supportScalar (float coord, const Triple &tent)
+static inline double supportScalar (double coord, const Triple &tent)
 {
   /* Copied from VarRegionAxis::evaluate() */
-  float start = tent.minimum, peak = tent.middle, end = tent.maximum;
+  double start = tent.minimum, peak = tent.middle, end = tent.maximum;
 
   if (unlikely (start > peak || peak > end))
     return 1.;
@@ -62,20 +62,20 @@
     return  (end - coord) / (end - peak);
 }
 
-static inline result_t
+static inline rebase_tent_result_t
 _solve (Triple tent, Triple axisLimit, bool negative = false)
 {
-  float axisMin = axisLimit.minimum;
-  float axisDef = axisLimit.middle;
-  float axisMax = axisLimit.maximum;
-  float lower = tent.minimum;
-  float peak  = tent.middle;
-  float upper = tent.maximum;
+  double axisMin = axisLimit.minimum;
+  double axisDef = axisLimit.middle;
+  double axisMax = axisLimit.maximum;
+  double lower = tent.minimum;
+  double peak  = tent.middle;
+  double upper = tent.maximum;
 
   // Mirror the problem such that axisDef <= peak
   if (axisDef > peak)
   {
-    result_t vec = _solve (_reverse_negate (tent),
+    rebase_tent_result_t vec = _solve (_reverse_negate (tent),
 			   _reverse_negate (axisLimit),
 			   !negative);
 
@@ -98,7 +98,7 @@
    *    axisMin     axisDef    axisMax   lower     upper
    */
   if (axisMax <= lower && axisMax < peak)
-      return result_t{};  // No overlap
+      return rebase_tent_result_t{};  // No overlap
 
   /* case 2: Only the peak and outermost bound fall outside the new limit;
    * we keep the deltaset, update peak and outermost bound and scale deltas
@@ -130,10 +130,10 @@
    */
   if (axisMax < peak)
   {
-    float mult = supportScalar (axisMax, tent);
+    double mult = supportScalar (axisMax, tent);
     tent = Triple{lower, axisMax, axisMax};
 
-    result_t vec = _solve (tent, axisLimit);
+    rebase_tent_result_t vec = _solve (tent, axisLimit);
 
     for (auto &p : vec)
       p = hb_pair (p.first * mult, p.second);
@@ -143,13 +143,13 @@
 
   // lower <= axisDef <= peak <= axisMax
 
-  float gain = supportScalar (axisDef, tent);
-  result_t out {hb_pair (gain, Triple{})};
+  double gain = supportScalar (axisDef, tent);
+  rebase_tent_result_t out {hb_pair (gain, Triple{})};
 
   // First, the positive side
 
   // outGain is the scalar of axisMax at the tent.
-  float outGain = supportScalar (axisMax, tent);
+  double outGain = supportScalar (axisMax, tent);
 
   /* Case 3a: Gain is more than outGain. The tent down-slope crosses
    * the axis into negative. We have to split it into multiples.
@@ -168,13 +168,15 @@
    *                           |
    *                      crossing
    */
-  if (gain > outGain)
+  if (gain >= outGain)
   {
-    // Crossing point on the axis.
-    float crossing = peak + (1 - gain) * (upper - peak);
+    // Note that this is the branch taken if both gain and outGain are 0.
 
-    Triple loc{axisDef, peak, crossing};
-    float scalar = 1.f;
+    // Crossing point on the axis.
+    double crossing = peak + (1 - gain) * (upper - peak);
+
+    Triple loc{hb_max (lower, axisDef), peak, crossing};
+    double scalar = 1.0;
 
     // The part before the crossing point.
     out.push (hb_pair (scalar - gain, loc));
@@ -189,7 +191,7 @@
     if (upper >= axisMax)
     {
       Triple loc {crossing, axisMax, axisMax};
-      float scalar = outGain;
+      double scalar = outGain;
 
       out.push (hb_pair (scalar - gain, loc));
     }
@@ -219,11 +221,11 @@
 
       // Downslope.
       Triple loc1 {crossing, upper, axisMax};
-      float scalar1 = 0.f;
+      double scalar1 = 0.0;
 
       // Eternity justify.
       Triple loc2 {upper, axisMax, axisMax};
-      float scalar2 = 0.f;
+      double scalar2 = 0.0;
 
       out.push (hb_pair (scalar1 - gain, loc1));
       out.push (hb_pair (scalar2 - gain, loc2));
@@ -252,9 +254,12 @@
      *                    |      |  newUpper
      *              axisDef      axisMax
      */
-    float newUpper = peak + (1 - gain) * (upper - peak);
-    assert (axisMax <= newUpper);  // Because outGain >= gain
-    if (newUpper <= axisDef + (axisMax - axisDef) * 2)
+    double newUpper = peak + (1 - gain) * (upper - peak);
+    assert (axisMax <= newUpper);  // Because outGain > gain
+    /* Disabled because ots doesn't like us:
+     * https://github.com/fonttools/fonttools/issues/3350 */
+
+    if (false && (newUpper <= axisDef + (axisMax - axisDef) * 2))
     {
       upper = newUpper;
       if (!negative && axisDef + (axisMax - axisDef) * MAX_F2DOT14 < upper)
@@ -265,7 +270,7 @@
       }
 
       Triple loc {hb_max (axisDef, lower), peak, upper};
-      float scalar = 1.f;
+      double scalar = 1.0;
 
       out.push (hb_pair (scalar - gain, loc));
     }
@@ -289,10 +294,10 @@
     else
     {
       Triple loc1 {hb_max (axisDef, lower), peak, axisMax};
-      float scalar1 = 1.f;
+      double scalar1 = 1.0;
 
       Triple loc2 {peak, axisMax, axisMax};
-      float scalar2 = outGain;
+      double scalar2 = outGain;
 
       out.push (hb_pair (scalar1 - gain, loc1));
       // Don't add a dirac delta!
@@ -320,7 +325,7 @@
   if (lower <= axisMin)
   {
     Triple loc {axisMin, axisMin, axisDef};
-    float scalar = supportScalar (axisMin, tent);
+    double scalar = supportScalar (axisMin, tent);
 
     out.push (hb_pair (scalar - gain, loc));
   }
@@ -348,11 +353,11 @@
 
     // Downslope.
     Triple loc1 {axisMin, lower, axisDef};
-    float scalar1 = 0.f;
+    double scalar1 = 0.0;
 
     // Eternity justify.
     Triple loc2 {axisMin, axisMin, lower};
-    float scalar2 = 0.f;
+    double scalar2 = 0.0;
 
     out.push (hb_pair (scalar1 - gain, loc1));
     out.push (hb_pair (scalar2 - gain, loc2));
@@ -364,19 +369,19 @@
 static inline TripleDistances _reverse_triple_distances (const TripleDistances &v)
 { return TripleDistances (v.positive, v.negative); }
 
-float renormalizeValue (float v, const Triple &triple,
-                        const TripleDistances &triple_distances, bool extrapolate)
+double renormalizeValue (double v, const Triple &triple,
+                         const TripleDistances &triple_distances, bool extrapolate)
 {
-  float lower = triple.minimum, def = triple.middle, upper = triple.maximum;
+  double lower = triple.minimum, def = triple.middle, upper = triple.maximum;
   assert (lower <= def && def <= upper);
 
   if (!extrapolate)
       v = hb_max (hb_min (v, upper), lower);
 
   if (v == def)
-    return 0.f;
+    return 0.0;
 
-  if (def < 0.f)
+  if (def < 0.0)
     return -renormalizeValue (-v, _reverse_negate (triple),
                               _reverse_triple_distances (triple_distances), extrapolate);
 
@@ -385,14 +390,14 @@
     return (v - def) / (upper - def);
 
   /* v < def */
-  if (lower >= 0.f)
+  if (lower >= 0.0)
     return (v - def) / (def - lower);
 
   /* lower < 0 and v < default */
-  float total_distance = triple_distances.negative * (-lower) + triple_distances.positive * def;
+  double total_distance = triple_distances.negative * (-lower) + triple_distances.positive * def;
 
-  float v_distance;
-  if (v >= 0.f)
+  double v_distance;
+  if (v >= 0.0)
     v_distance = (def - v) * triple_distances.positive;
   else
     v_distance = (-v) * triple_distances.negative + triple_distances.positive * def;
@@ -400,18 +405,18 @@
   return (-v_distance) /total_distance;
 }
 
-result_t
+rebase_tent_result_t
 rebase_tent (Triple tent, Triple axisLimit, TripleDistances axis_triple_distances)
 {
-  assert (-1.f <= axisLimit.minimum && axisLimit.minimum <= axisLimit.middle && axisLimit.middle <= axisLimit.maximum && axisLimit.maximum <= +1.f);
-  assert (-2.f <= tent.minimum && tent.minimum <= tent.middle && tent.middle <= tent.maximum && tent.maximum <= +2.f);
-  assert (tent.middle != 0.f);
+  assert (-1.0 <= axisLimit.minimum && axisLimit.minimum <= axisLimit.middle && axisLimit.middle <= axisLimit.maximum && axisLimit.maximum <= +1.0);
+  assert (-2.0 <= tent.minimum && tent.minimum <= tent.middle && tent.middle <= tent.maximum && tent.maximum <= +2.0);
+  assert (tent.middle != 0.0);
 
-  result_t sols = _solve (tent, axisLimit);
+  rebase_tent_result_t sols = _solve (tent, axisLimit);
 
-  auto n = [&axisLimit, &axis_triple_distances] (float v) { return renormalizeValue (v, axisLimit, axis_triple_distances); };
+  auto n = [&axisLimit, &axis_triple_distances] (double v) { return renormalizeValue (v, axisLimit, axis_triple_distances); };
 
-  result_t out;
+  rebase_tent_result_t out;
   for (auto &p : sols)
   {
     if (!p.first) continue;
diff --git a/src/hb-subset-instancer-solver.hh b/src/hb-subset-instancer-solver.hh
index 563fccb..9aac9fc 100644
--- a/src/hb-subset-instancer-solver.hh
+++ b/src/hb-subset-instancer-solver.hh
@@ -30,24 +30,24 @@
 /* pre-normalized distances */
 struct TripleDistances
 {
-  TripleDistances (): negative (1.f), positive (1.f) {}
-  TripleDistances (float neg_, float pos_): negative (neg_), positive (pos_) {}
-  TripleDistances (float min, float default_, float max)
+  TripleDistances (): negative (1.0), positive (1.0) {}
+  TripleDistances (double neg_, double pos_): negative (neg_), positive (pos_) {}
+  TripleDistances (double min, double default_, double max)
   {
     negative = default_ - min;
     positive = max - default_;
   }
 
-  float negative;
-  float positive;
+  double negative;
+  double positive;
 };
 
 struct Triple {
 
   Triple () :
-    minimum (0.f), middle (0.f), maximum (0.f) {}
+    minimum (0.0), middle (0.0), maximum (0.0) {}
 
-  Triple (float minimum_, float middle_, float maximum_) :
+  Triple (double minimum_, double middle_, double maximum_) :
     minimum (minimum_), middle (middle_), maximum (maximum_) {}
 
   bool operator == (const Triple &o) const
@@ -63,7 +63,7 @@
   bool is_point () const
   { return minimum == middle && middle == maximum; }
 
-  bool contains (float point) const
+  bool contains (double point) const
   { return minimum <= point && point <= maximum; }
 
   /* from hb_array_t hash ()*/
@@ -82,18 +82,18 @@
   }
 
 
-  float minimum;
-  float middle;
-  float maximum;
+  double minimum;
+  double middle;
+  double maximum;
 };
 
-using result_item_t = hb_pair_t<float, Triple>;
-using result_t = hb_vector_t<result_item_t>;
+using rebase_tent_result_item_t = hb_pair_t<double, Triple>;
+using rebase_tent_result_t = hb_vector_t<rebase_tent_result_item_t>;
 
 /* renormalize a normalized value v to the range of an axis,
  * considering the prenormalized distances as well as the new axis limits.
  * Ported from fonttools */
-HB_INTERNAL float renormalizeValue (float v, const Triple &triple,
+HB_INTERNAL double renormalizeValue (double v, const Triple &triple,
                                     const TripleDistances &triple_distances,
                                     bool extrapolate = true);
 /* Given a tuple (lower,peak,upper) "tent" and new axis limits
@@ -107,6 +107,8 @@
  * If tent value is Triple{}, that is a special deltaset that should
  * be always-enabled (called "gain").
  */
-HB_INTERNAL result_t rebase_tent (Triple tent, Triple axisLimit, TripleDistances axis_triple_distances);
+HB_INTERNAL rebase_tent_result_t rebase_tent (Triple tent,
+					      Triple axisLimit,
+					      TripleDistances axis_triple_distances);
 
 #endif /* HB_SUBSET_INSTANCER_SOLVER_HH */
diff --git a/src/hb-subset-plan-member-list.hh b/src/hb-subset-plan-member-list.hh
index 8bc1fcb..ade8278 100644
--- a/src/hb-subset-plan-member-list.hh
+++ b/src/hb-subset-plan-member-list.hh
@@ -70,6 +70,9 @@
 HB_SUBSET_PLAN_MEMBER (hb_map_t, gsub_lookups)
 HB_SUBSET_PLAN_MEMBER (hb_map_t, gpos_lookups)
 
+//use_mark_sets mapping: old->new
+HB_SUBSET_PLAN_MEMBER (hb_map_t, used_mark_sets_map)
+
 //active langsys we'd like to retain
 HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, hb::unique_ptr<hb_set_t>>), gsub_langsys)
 HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, hb::unique_ptr<hb_set_t>>), gpos_langsys)
@@ -87,9 +90,24 @@
 HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, const OT::Feature*>), gsub_feature_substitutes_map)
 HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, const OT::Feature*>), gpos_feature_substitutes_map)
 
+// old feature_indexes set, used to reinstate the old features
+HB_SUBSET_PLAN_MEMBER (hb_set_t, gsub_old_features)
+HB_SUBSET_PLAN_MEMBER (hb_set_t, gpos_old_features)
+
+//feature_index->pair of (address of old feature, feature tag), used for inserting a catch all record
+//if necessary
+HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, hb_pair_t E(<const void*, const void*>)>), gsub_old_feature_idx_tag_map)
+HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, hb_pair_t E(<const void*, const void*>)>), gpos_old_feature_idx_tag_map)
+
 //active layers/palettes we'd like to retain
 HB_SUBSET_PLAN_MEMBER (hb_map_t, colrv1_layers)
 HB_SUBSET_PLAN_MEMBER (hb_map_t, colr_palettes)
+//colrv1 varstore retained varidx mapping
+HB_SUBSET_PLAN_MEMBER (hb_vector_t<hb_inc_bimap_t>, colrv1_varstore_inner_maps)
+//colrv1 retained varidx -> (new varidx, delta) mapping
+HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<unsigned, hb_pair_t E(<unsigned, int>)>), colrv1_variation_idx_delta_map)
+//colrv1 retained new delta set index -> new varidx mapping
+HB_SUBSET_PLAN_MEMBER (hb_map_t, colrv1_new_deltaset_idx_varidx_map)
 
 //Old layout item variation index -> (New varidx, delta) mapping
 HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<unsigned, hb_pair_t E(<unsigned, int>)>), layout_variation_idx_delta_map)
@@ -128,6 +146,15 @@
 //map: new_gid -> contour points vector
 HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<hb_codepoint_t, contour_point_vector_t>), new_gid_contour_points_map)
 
+//new gids set for composite glyphs
+HB_SUBSET_PLAN_MEMBER (hb_set_t, composite_new_gids)
+
+//Old BASE item variation index -> (New varidx, 0) mapping
+HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<unsigned, hb_pair_t E(<unsigned, int>)>), base_variation_idx_map)
+
+//BASE table varstore retained varidx mapping
+HB_SUBSET_PLAN_MEMBER (hb_vector_t<hb_inc_bimap_t>, base_varstore_inner_maps)
+
 #ifdef HB_EXPERIMENTAL_API
 // name table overrides map: hb_ot_name_record_ids_t-> name string new value or
 // None to indicate should remove
diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc
index c688b71..d657790 100644
--- a/src/hb-subset-plan.cc
+++ b/src/hb-subset-plan.cc
@@ -32,6 +32,7 @@
 
 #include "hb-ot-cmap-table.hh"
 #include "hb-ot-glyf-table.hh"
+#include "hb-ot-layout-base-table.hh"
 #include "hb-ot-layout-gdef-table.hh"
 #include "hb-ot-layout-gpos-table.hh"
 #include "hb-ot-layout-gsub-table.hh"
@@ -150,7 +151,8 @@
                                      hb_set_t		  *feature_indices, /* OUT */
                                      hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map, /* OUT */
                                      hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map, /* OUT */
-                                     bool& insert_catch_all_feature_variation_record)
+                                     hb_set_t& catch_all_record_feature_idxes, /* OUT */
+                                     hb_hashmap_t<unsigned, hb_pair_t<const void*, const void*>>& catch_all_record_idx_feature_map /* OUT */)
 {
   unsigned num_features = table.get_feature_count ();
   hb_vector_t<hb_tag_t> features;
@@ -186,7 +188,7 @@
       &plan->axes_location,
       feature_record_cond_idx_map,
       feature_substitutes_map,
-      insert_catch_all_feature_variation_record,
+      catch_all_record_feature_idxes,
       feature_indices,
       false,
       false,
@@ -208,17 +210,25 @@
     f->add_lookup_indexes_to (lookup_indices);
   }
 
+#ifndef HB_NO_VAR
+  if (catch_all_record_feature_idxes)
+  {
+    for (unsigned feature_index : catch_all_record_feature_idxes)
+    {
+      const OT::Feature& f = table.get_feature (feature_index);
+      f.add_lookup_indexes_to (lookup_indices);
+      const void *tag = reinterpret_cast<const void*> (&(table.get_feature_list ().get_tag (feature_index)));
+      catch_all_record_idx_feature_map.set (feature_index, hb_pair (&f, tag));
+    }
+  }
+
   // If all axes are pinned then all feature variations will be dropped so there's no need
   // to collect lookups from them.
   if (!plan->all_axes_pinned)
-  {
-    // TODO(qxliu76): this collection doesn't work correctly for feature variations that are dropped
-    //                but not applied. The collection will collect and retain the lookup indices
-    //                associated with those dropped but not activated rules. Since partial instancing
-    //                isn't yet supported this isn't an issue yet but will need to be fixed for
-    //                partial instancing.
-    table.feature_variation_collect_lookups (feature_indices, feature_substitutes_map, lookup_indices);
-  }
+    table.feature_variation_collect_lookups (feature_indices,
+                                             plan->user_axes_location.is_empty () ? nullptr: feature_record_cond_idx_map,
+                                             lookup_indices);
+#endif
 }
 
 
@@ -302,7 +312,8 @@
 				  script_langsys_map *langsys_map,
 				  hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map,
 				  hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map,
-				  bool& insert_catch_all_feature_variation_record)
+                                  hb_set_t &catch_all_record_feature_idxes,
+                                  hb_hashmap_t<unsigned, hb_pair_t<const void*, const void*>>& catch_all_record_idx_feature_map)
 {
   hb_blob_ptr_t<T> table = plan->source_table<T> ();
   hb_tag_t table_tag = table->tableTag;
@@ -313,7 +324,8 @@
                               &feature_indices,
                               feature_record_cond_idx_map,
                               feature_substitutes_map,
-                              insert_catch_all_feature_variation_record);
+                              catch_all_record_feature_idxes,
+                              catch_all_record_idx_feature_map);
 
   if (table_tag == HB_OT_TAG_GSUB && !(plan->flags & HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE))
     hb_ot_layout_lookups_substitute_closure (plan->source,
@@ -387,12 +399,55 @@
 }
 
 static inline void
+_remap_variation_indices (const OT::ItemVariationStore &var_store,
+                          const hb_set_t &variation_indices,
+                          const hb_vector_t<int>& normalized_coords,
+                          bool calculate_delta, /* not pinned at default */
+                          bool no_variations, /* all axes pinned */
+                          hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> &variation_idx_delta_map /* OUT */)
+{
+  if (&var_store == &Null (OT::ItemVariationStore)) return;
+  unsigned subtable_count = var_store.get_sub_table_count ();
+  float *store_cache = var_store.create_cache ();
+
+  unsigned new_major = 0, new_minor = 0;
+  unsigned last_major = (variation_indices.get_min ()) >> 16;
+  for (unsigned idx : variation_indices)
+  {
+    int delta = 0;
+    if (calculate_delta)
+      delta = roundf (var_store.get_delta (idx, normalized_coords.arrayZ,
+                                           normalized_coords.length, store_cache));
+
+    if (no_variations)
+    {
+      variation_idx_delta_map.set (idx, hb_pair_t<unsigned, int> (HB_OT_LAYOUT_NO_VARIATIONS_INDEX, delta));
+      continue;
+    }
+
+    uint16_t major = idx >> 16;
+    if (major >= subtable_count) break;
+    if (major != last_major)
+    {
+      new_minor = 0;
+      ++new_major;
+    }
+
+    unsigned new_idx = (new_major << 16) + new_minor;
+    variation_idx_delta_map.set (idx, hb_pair_t<unsigned, int> (new_idx, delta));
+    ++new_minor;
+    last_major = major;
+  }
+  var_store.destroy_cache (store_cache);
+}
+
+static inline void
 _collect_layout_variation_indices (hb_subset_plan_t* plan)
 {
   hb_blob_ptr_t<OT::GDEF> gdef = plan->source_table<OT::GDEF> ();
   hb_blob_ptr_t<GPOS> gpos = plan->source_table<GPOS> ();
 
-  if (!gdef->has_data ())
+  if (!gdef->has_data () || !gdef->has_var_store ())
   {
     gdef.destroy ();
     gpos.destroy ();
@@ -408,18 +463,47 @@
   if (hb_ot_layout_has_positioning (plan->source))
     gpos->collect_variation_indices (&c);
 
-  gdef->remap_layout_variation_indices (&varidx_set,
-                                        plan->normalized_coords,
-                                        !plan->pinned_at_default,
-                                        plan->all_axes_pinned,
-                                        &plan->layout_variation_idx_delta_map);
+  _remap_variation_indices (gdef->get_var_store (),
+                            varidx_set, plan->normalized_coords,
+                            !plan->pinned_at_default,
+                            plan->all_axes_pinned,
+                            plan->layout_variation_idx_delta_map);
 
-  unsigned subtable_count = gdef->has_var_store () ? gdef->get_var_store ().get_sub_table_count () : 0;
+  unsigned subtable_count = gdef->get_var_store ().get_sub_table_count ();
   _generate_varstore_inner_maps (varidx_set, subtable_count, plan->gdef_varstore_inner_maps);
 
   gdef.destroy ();
   gpos.destroy ();
 }
+
+#ifndef HB_NO_BASE
+static inline void
+_collect_base_variation_indices (hb_subset_plan_t* plan)
+{
+  hb_blob_ptr_t<OT::BASE> base = plan->source_table<OT::BASE> ();
+  if (!base->has_var_store ())
+  {
+    base.destroy ();
+    return;
+  }
+
+  hb_set_t varidx_set;
+  base->collect_variation_indices (plan, varidx_set);
+  const OT::ItemVariationStore &var_store = base->get_var_store ();
+  unsigned subtable_count = var_store.get_sub_table_count ();
+  
+
+  _remap_variation_indices (var_store, varidx_set,
+                            plan->normalized_coords,
+                            !plan->pinned_at_default,
+                            plan->all_axes_pinned,
+                            plan->base_variation_idx_map);
+  _generate_varstore_inner_maps (varidx_set, subtable_count, plan->base_varstore_inner_maps);
+
+  base.destroy ();
+}
+
+#endif
 #endif
 
 static inline void
@@ -431,12 +515,43 @@
   cmap.table->closure_glyphs (unicodes, glyphset);
 }
 
-static void _colr_closure (hb_face_t *face,
-                           hb_map_t *layers_map,
-                           hb_map_t *palettes_map,
+static void
+_remap_colrv1_delta_set_index_indices (const OT::DeltaSetIndexMap &index_map,
+                                       const hb_set_t &delta_set_idxes,
+                                       hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> &variation_idx_delta_map, /* IN/OUT */
+                                       hb_map_t &new_deltaset_idx_varidx_map /* OUT */)
+{
+  if (!index_map.get_map_count ())
+    return;
+
+  hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> delta_set_idx_delta_map;
+  unsigned new_delta_set_idx = 0;
+  for (unsigned delta_set_idx : delta_set_idxes)
+  {
+    unsigned var_idx = index_map.map (delta_set_idx);
+    unsigned new_varidx = HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
+    int delta = 0;
+    
+    if (var_idx != HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
+    {
+      hb_pair_t<unsigned, int> *new_varidx_delta;
+      if (!variation_idx_delta_map.has (var_idx, &new_varidx_delta)) continue;
+
+      new_varidx = hb_first (*new_varidx_delta);
+      delta = hb_second (*new_varidx_delta);
+    }
+
+    new_deltaset_idx_varidx_map.set (new_delta_set_idx, new_varidx);
+    delta_set_idx_delta_map.set (delta_set_idx, hb_pair_t<unsigned, int> (new_delta_set_idx, delta));
+    new_delta_set_idx++;
+  }
+  variation_idx_delta_map = std::move (delta_set_idx_delta_map);
+}
+
+static void _colr_closure (hb_subset_plan_t* plan,
                            hb_set_t *glyphs_colred)
 {
-  OT::COLR::accelerator_t colr (face);
+  OT::COLR::accelerator_t colr (plan->source);
   if (!colr.is_valid ()) return;
 
   hb_set_t palette_indices, layer_indices;
@@ -448,11 +563,43 @@
   glyphs_colred->union_ (glyphset_colrv0);
 
   //closure for COLRv1
-  colr.closure_forV1 (glyphs_colred, &layer_indices, &palette_indices);
+  hb_set_t variation_indices, delta_set_indices;
+  colr.closure_forV1 (glyphs_colred, &layer_indices, &palette_indices, &variation_indices, &delta_set_indices);
 
   colr.closure_V0palette_indices (glyphs_colred, &palette_indices);
-  _remap_indexes (&layer_indices, layers_map);
-  _remap_palette_indexes (&palette_indices, palettes_map);
+  _remap_indexes (&layer_indices, &plan->colrv1_layers);
+  _remap_palette_indexes (&palette_indices, &plan->colr_palettes);
+
+  if (!colr.has_var_store () || !variation_indices) return;
+
+  const OT::ItemVariationStore &var_store = colr.get_var_store ();
+  // generated inner_maps is used by ItemVariationStore serialize(), which is subset only
+  unsigned subtable_count = var_store.get_sub_table_count ();
+  _generate_varstore_inner_maps (variation_indices, subtable_count, plan->colrv1_varstore_inner_maps);
+
+  /* colr variation indices mapping during planning phase:
+   * generate colrv1_variation_idx_delta_map. When delta set index map is not
+   * included, it's a mapping from varIdx-> (new varIdx,delta). Otherwise, it's
+   * a mapping from old delta set idx-> (new delta set idx, delta). Mapping
+   * delta set indices is the same as gid mapping.
+   * Besides, we need to generate a delta set idx-> new var_idx map for updating
+   * delta set index map if exists. This map will be updated again after
+   * instancing. */
+  if (!plan->all_axes_pinned)
+  {
+    _remap_variation_indices (var_store,
+                              variation_indices,
+                              plan->normalized_coords,
+                              false, /* no need to calculate delta for COLR during planning */
+                              plan->all_axes_pinned,
+                              plan->colrv1_variation_idx_delta_map);
+
+    if (colr.has_delta_set_index_map ())
+      _remap_colrv1_delta_set_index_indices (colr.get_delta_set_index_map (),
+                                             delta_set_indices,
+                                             plan->colrv1_variation_idx_delta_map,
+                                             plan->colrv1_new_deltaset_idx_varidx_map);
+  }
 }
 
 static inline void
@@ -465,6 +612,24 @@
   math.destroy ();
 }
 
+static inline void
+_remap_used_mark_sets (hb_subset_plan_t *plan,
+                       hb_map_t& used_mark_sets_map)
+{
+  hb_blob_ptr_t<OT::GDEF> gdef = plan->source_table<OT::GDEF> ();
+
+  if (!gdef->has_data () || !gdef->has_mark_glyph_sets ())
+  {
+    gdef.destroy ();
+    return;
+  }
+
+  hb_set_t used_mark_sets;
+  gdef->get_mark_glyph_sets ().collect_used_mark_sets (plan->_glyphset_gsub, used_mark_sets);
+  gdef.destroy ();
+
+  _remap_indexes (&used_mark_sets, &used_mark_sets_map);
+}
 
 static inline void
 _remove_invalid_gids (hb_set_t *glyphs,
@@ -578,14 +743,18 @@
     else
     {
       plan->codepoint_to_glyph->alloc (cmap_unicodes->get_population ());
-      for (hb_codepoint_t cp : *cmap_unicodes)
+      hb_codepoint_t first = HB_SET_VALUE_INVALID, last = HB_SET_VALUE_INVALID;
+      for (; cmap_unicodes->next_range (&first, &last); )
       {
-	hb_codepoint_t gid = (*unicode_glyphid_map)[cp];
-	if (!unicodes->has (cp) && !glyphs->has (gid))
-	  continue;
+        for (unsigned cp = first; cp <= last; cp++)
+	{
+	  hb_codepoint_t gid = (*unicode_glyphid_map)[cp];
+	  if (!unicodes->has (cp) && !glyphs->has (gid))
+	    continue;
 
-	plan->codepoint_to_glyph->set (cp, gid);
-	plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
+	  plan->codepoint_to_glyph->set (cp, gid);
+	  plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
+	}
       }
     }
 
@@ -714,7 +883,8 @@
         &plan->gsub_langsys,
         &plan->gsub_feature_record_cond_idx_map,
         &plan->gsub_feature_substitutes_map,
-        plan->gsub_insert_catch_all_feature_variation_rec);
+        plan->gsub_old_features,
+        plan->gsub_old_feature_idx_tag_map);
 
   if (!drop_tables->has (HB_OT_TAG_GPOS))
     _closure_glyphs_lookups_features<GPOS> (
@@ -725,7 +895,8 @@
         &plan->gpos_langsys,
         &plan->gpos_feature_record_cond_idx_map,
         &plan->gpos_feature_substitutes_map,
-        plan->gpos_insert_catch_all_feature_variation_rec);
+        plan->gpos_old_features,
+        plan->gpos_old_feature_idx_tag_map);
 #endif
   _remove_invalid_gids (&plan->_glyphset_gsub, plan->source->get_num_glyphs ());
 
@@ -739,7 +910,7 @@
   hb_set_t cur_glyphset = plan->_glyphset_mathed;
   if (!drop_tables->has (HB_OT_TAG_COLR))
   {
-    _colr_closure (plan->source, &plan->colrv1_layers, &plan->colr_palettes, &cur_glyphset);
+    _colr_closure (plan, &cur_glyphset);
     _remove_invalid_gids (&cur_glyphset, plan->source->get_num_glyphs ());
   }
 
@@ -814,12 +985,12 @@
 
     if (retain_gids)
     {
-      DEBUG_MSG (SUBSET, nullptr, 
+      DEBUG_MSG (SUBSET, nullptr,
         "HB_SUBSET_FLAGS_RETAIN_GIDS cannot be set if "
         "a custom glyph mapping has been provided.");
       return false;
     }
-  
+
     hb_codepoint_t max_glyph = 0;
     hb_set_t remaining;
     for (auto old_gid : all_gids_to_retain->iter ())
@@ -871,9 +1042,11 @@
     *num_glyphs = max_glyph + 1;
   }
 
+  reverse_glyph_map->alloc (reverse_glyph_map->get_population () + new_to_old_gid_list->length);
   + hb_iter (new_to_old_gid_list)
   | hb_sink (reverse_glyph_map)
   ;
+  glyph_map->alloc (glyph_map->get_population () + new_to_old_gid_list->length);
   + hb_iter (new_to_old_gid_list)
   | hb_map (&hb_codepoint_pair_t::reverse)
   | hb_sink (glyph_map)
@@ -932,9 +1105,9 @@
         normalized_default = seg_maps->map (normalized_default);
         normalized_max = seg_maps->map (normalized_max);
       }
-      plan->axes_location.set (axis_tag, Triple (static_cast<float> (normalized_min / 16384.f),
-                                                 static_cast<float> (normalized_default / 16384.f),
-                                                 static_cast<float> (normalized_max / 16384.f)));
+      plan->axes_location.set (axis_tag, Triple (static_cast<double> (normalized_min / 16384.0),
+                                                 static_cast<double> (normalized_default / 16384.0),
+                                                 static_cast<double> (normalized_max / 16384.0)));
 
       if (normalized_default != 0)
         plan->pinned_at_default = false;
@@ -957,8 +1130,8 @@
   OT::cff2::accelerator_t cff2 (plan->source);
   if (!cff2.is_valid ()) return;
 
-  hb_font_t *font = nullptr;
-  if (unlikely (!plan->check_success (font = _get_hb_font_with_variations (plan))))
+  hb_font_t *font = _get_hb_font_with_variations (plan);
+  if (unlikely (!plan->check_success (font != nullptr)))
   {
     hb_font_destroy (font);
     return;
@@ -969,7 +1142,7 @@
   float *hvar_store_cache = nullptr;
   if (_hmtx.has_data () && _hmtx.var_table.get_length ())
     hvar_store_cache = _hmtx.var_table->get_var_store ().create_cache ();
-  
+
   OT::vmtx_accelerator_t _vmtx (plan->source);
   float *vvar_store_cache = nullptr;
   if (_vmtx.has_data () && _vmtx.var_table.get_length ())
@@ -1036,8 +1209,8 @@
 static bool
 _get_instance_glyphs_contour_points (hb_subset_plan_t *plan)
 {
-  /* contour_points vector only needed for updating gvar table (infer delta)
-   * during partial instancing */
+  /* contour_points vector only needed for updating gvar table (infer delta and
+   * iup delta optimization) during partial instancing */
   if (plan->user_axes_location.is_empty () || plan->all_axes_pinned)
     return true;
 
@@ -1055,10 +1228,15 @@
     }
 
     hb_codepoint_t old_gid = _.second;
-    if (unlikely (!glyf.glyph_for_gid (old_gid).get_all_points_without_var (plan->source, all_points)))
+    auto glyph = glyf.glyph_for_gid (old_gid);
+    if (unlikely (!glyph.get_all_points_without_var (plan->source, all_points)))
       return false;
     if (unlikely (!plan->new_gid_contour_points_map.set (new_gid, all_points)))
       return false;
+
+    /* composite new gids are only needed by iup delta optimization */
+    if ((plan->flags & HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS) && glyph.is_composite ())
+      plan->composite_new_gids.add (new_gid);
   }
   return true;
 }
@@ -1093,6 +1271,7 @@
   user_axes_location = input->axes_location;
   all_axes_pinned = false;
   pinned_at_default = true;
+  has_gdef_varstore = false;
 
 #ifdef HB_EXPERIMENTAL_API
   for (auto _ : input->name_table_overrides)
@@ -1112,6 +1291,10 @@
 
   attach_accelerator_data = input->attach_accelerator_data;
   force_long_loca = input->force_long_loca;
+#ifdef HB_EXPERIMENTAL_API
+  force_long_loca = force_long_loca || (flags & HB_SUBSET_FLAGS_IFTB_REQUIREMENTS);
+#endif
+
   if (accel)
     accelerator = (hb_subset_accelerator_t*) accel;
 
@@ -1160,6 +1343,16 @@
   for (auto &v : bounds_height_vec)
     v = 0xFFFFFFFF;
 
+  if (!drop_tables.has (HB_OT_TAG_GDEF))
+    _remap_used_mark_sets (this, used_mark_sets_map);
+
+#ifndef HB_NO_VAR
+#ifndef HB_NO_BASE
+  if (!drop_tables.has (HB_OT_TAG_BASE))
+    _collect_base_variation_indices (this);
+#endif
+#endif
+
   if (unlikely (in_error ()))
     return;
 
diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh
index a05d1d1..19a9fa6 100644
--- a/src/hb-subset-plan.hh
+++ b/src/hb-subset-plan.hh
@@ -78,6 +78,13 @@
 	  y  = x * matrix[1] + y * matrix[3];
     x  = x_;
   }
+
+  void add_delta (float delta_x, float delta_y)
+  {
+    x += delta_x;
+    y += delta_y;
+  }
+
   HB_ALWAYS_INLINE
   void translate (const contour_point_t &p) { x += p.x; y += p.y; }
 
@@ -99,6 +106,22 @@
     unsigned count = a.length;
     hb_memcpy (arrayZ, a.arrayZ, count * sizeof (arrayZ[0]));
   }
+
+  bool add_deltas (const hb_vector_t<float> deltas_x,
+                   const hb_vector_t<float> deltas_y,
+                   const hb_vector_t<bool> indices)
+  {
+    if (indices.length != deltas_x.length ||
+        indices.length != deltas_y.length)
+      return false;
+
+    for (unsigned i = 0; i < indices.length; i++)
+    {
+      if (!indices.arrayZ[i]) continue;
+      arrayZ[i].add_delta (deltas_x.arrayZ[i], deltas_y.arrayZ[i]);
+    }
+    return true;
+  }
 };
 
 namespace OT {
@@ -147,6 +170,9 @@
   bool gsub_insert_catch_all_feature_variation_rec;
   bool gpos_insert_catch_all_feature_variation_rec;
 
+  // whether GDEF ItemVariationStore is retained
+  mutable bool has_gdef_varstore;
+
 #define HB_SUBSET_PLAN_MEMBER(Type, Name) Type Name;
 #include "hb-subset-plan-member-list.hh"
 #undef HB_SUBSET_PLAN_MEMBER
diff --git a/src/hb-subset.cc b/src/hb-subset.cc
index 229b1c3..f10ef54 100644
--- a/src/hb-subset.cc
+++ b/src/hb-subset.cc
@@ -48,6 +48,7 @@
 #include "hb-ot-cff2-table.hh"
 #include "hb-ot-vorg-table.hh"
 #include "hb-ot-name-table.hh"
+#include "hb-ot-layout-base-table.hh"
 #include "hb-ot-layout-gsub-table.hh"
 #include "hb-ot-layout-gpos-table.hh"
 #include "hb-ot-var-avar-table.hh"
@@ -460,9 +461,10 @@
   case HB_OT_TAG_hmtx:
   case HB_OT_TAG_vmtx:
   case HB_OT_TAG_maxp:
+  case HB_OT_TAG_OS2:
     return !plan->normalized_coords || !pending_subset_tags.has (HB_OT_TAG_glyf);
   case HB_OT_TAG_GPOS:
-    return !plan->normalized_coords || plan->all_axes_pinned || !pending_subset_tags.has (HB_OT_TAG_GDEF);
+    return plan->all_axes_pinned || !pending_subset_tags.has (HB_OT_TAG_GDEF);
   default:
     return true;
   }
@@ -502,6 +504,7 @@
   case HB_OT_TAG_CBLC: return _subset<const OT::CBLC> (plan, buf);
   case HB_OT_TAG_CBDT: return true; /* skip CBDT, handled by CBLC */
   case HB_OT_TAG_MATH: return _subset<const OT::MATH> (plan, buf);
+  case HB_OT_TAG_BASE: return _subset<const OT::BASE> (plan, buf);
 
 #ifndef HB_NO_SUBSET_CFF
   case HB_OT_TAG_CFF1: return _subset<const OT::cff1> (plan, buf);
@@ -547,6 +550,7 @@
     }
 #endif
     return _passthrough (plan, tag);
+
   default:
     if (plan->flags & HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED)
       return _passthrough (plan, tag);
diff --git a/src/hb-subset.h b/src/hb-subset.h
index 4c35699..365c21a 100644
--- a/src/hb-subset.h
+++ b/src/hb-subset.h
@@ -73,6 +73,11 @@
  * OS/2 will not be recalculated.
  * @HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE: If set don't perform glyph closure on layout
  * substitution rules (GSUB). Since: 7.2.0.
+ * @HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS: If set perform IUP delta optimization on the
+ * remaining gvar table's deltas. Since: 8.5.0
+ * @HB_SUBSET_FLAGS_IFTB_REQUIREMENTS: If set enforce requirements on the output subset
+ * to allow it to be used with incremental font transfer IFTB patches. Primarily,
+ * this forces all outline data to use long (32 bit) offsets. Since: EXPERIMENTAL
  *
  * List of boolean properties that can be configured on the subset input.
  *
@@ -90,6 +95,10 @@
   HB_SUBSET_FLAGS_GLYPH_NAMES =		     0x00000080u,
   HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES =  0x00000100u,
   HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE =        0x00000200u,
+  HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS	  =  0x00000400u,
+#ifdef HB_EXPERIMENTAL_API
+  HB_SUBSET_FLAGS_IFTB_REQUIREMENTS       =  0x00000800u,
+#endif
 } hb_subset_flags_t;
 
 /**
@@ -165,6 +174,10 @@
 			   unsigned value);
 
 HB_EXTERN hb_bool_t
+hb_subset_input_pin_all_axes_to_default (hb_subset_input_t  *input,
+					 hb_face_t          *face);
+
+HB_EXTERN hb_bool_t
 hb_subset_input_pin_axis_to_default (hb_subset_input_t  *input,
 				     hb_face_t          *face,
 				     hb_tag_t            axis_tag);
@@ -175,15 +188,22 @@
 				   hb_tag_t            axis_tag,
 				   float               axis_value);
 
-#ifdef HB_EXPERIMENTAL_API
+HB_EXTERN hb_bool_t
+hb_subset_input_get_axis_range (hb_subset_input_t  *input,
+				hb_tag_t            axis_tag,
+				float              *axis_min_value,
+				float              *axis_max_value,
+				float              *axis_def_value);
+
 HB_EXTERN hb_bool_t
 hb_subset_input_set_axis_range (hb_subset_input_t  *input,
 				hb_face_t          *face,
 				hb_tag_t            axis_tag,
 				float               axis_min_value,
 				float               axis_max_value,
-				float              *axis_def_value);
+				float               axis_def_value);
 
+#ifdef HB_EXPERIMENTAL_API
 HB_EXTERN hb_bool_t
 hb_subset_input_override_name_table (hb_subset_input_t  *input,
 				     hb_ot_name_id_t     name_id,
@@ -192,7 +212,6 @@
 				     unsigned            language_id,
 				     const char         *name_str,
 				     int                 str_len);
-
 #endif
 
 HB_EXTERN hb_face_t *
diff --git a/src/hb-vector.hh b/src/hb-vector.hh
index 13cfe56..c0cc706 100644
--- a/src/hb-vector.hh
+++ b/src/hb-vector.hh
@@ -37,6 +37,8 @@
 	  bool sorted=false>
 struct hb_vector_t
 {
+  static constexpr bool realloc_move = true;
+
   typedef Type item_t;
   static constexpr unsigned item_size = hb_static_size (Type);
   using array_t = typename std::conditional<sorted, hb_sorted_array_t<Type>, hb_array_t<Type>>::type;
@@ -76,7 +78,7 @@
     if (unlikely (in_error ())) return;
     copy_array (o);
   }
-  hb_vector_t (hb_vector_t &&o)
+  hb_vector_t (hb_vector_t &&o) noexcept
   {
     allocated = o.allocated;
     length = o.length;
@@ -120,7 +122,7 @@
     resize (0);
   }
 
-  friend void swap (hb_vector_t& a, hb_vector_t& b)
+  friend void swap (hb_vector_t& a, hb_vector_t& b) noexcept
   {
     hb_swap (a.allocated, b.allocated);
     hb_swap (a.length, b.length);
@@ -137,7 +139,7 @@
 
     return *this;
   }
-  hb_vector_t& operator = (hb_vector_t &&o)
+  hb_vector_t& operator = (hb_vector_t &&o) noexcept
   {
     hb_swap (*this, o);
     return *this;
@@ -268,10 +270,9 @@
     }
     return new_array;
   }
-  /* Specialization for hb_vector_t<hb_{vector,array}_t<U>> to speed up. */
+  /* Specialization for types that can be moved using realloc(). */
   template <typename T = Type,
-	    hb_enable_if (hb_is_same (T, hb_vector_t<typename T::item_t>) ||
-			  hb_is_same (T, hb_array_t <typename T::item_t>))>
+	    hb_enable_if (T::realloc_move)>
   Type *
   realloc_vector (unsigned new_allocated, hb_priority<1>)
   {
diff --git a/src/hb-version.h b/src/hb-version.h
index cd7257e..abffbda 100644
--- a/src/hb-version.h
+++ b/src/hb-version.h
@@ -47,20 +47,20 @@
  *
  * The minor component of the library version available at compile-time.
  */
-#define HB_VERSION_MINOR 2
+#define HB_VERSION_MINOR 5
 /**
  * HB_VERSION_MICRO:
  *
  * The micro component of the library version available at compile-time.
  */
-#define HB_VERSION_MICRO 2
+#define HB_VERSION_MICRO 0
 
 /**
  * HB_VERSION_STRING:
  *
  * A string literal containing the library version available at compile-time.
  */
-#define HB_VERSION_STRING "8.2.2"
+#define HB_VERSION_STRING "8.5.0"
 
 /**
  * HB_VERSION_ATLEAST:
diff --git a/src/hb-wasm-api.h b/src/hb-wasm-api.h
index f9bd98e..bb977ee 100644
--- a/src/hb-wasm-api.h
+++ b/src/hb-wasm-api.h
@@ -27,6 +27,9 @@
 
 /*
 #include "hb.h"
+
+HB_BEGIN_DECLS
+HB_END_DECLS
 */
 
 #include <stdint.h>
diff --git a/src/hb-wasm-shape.cc b/src/hb-wasm-shape.cc
index a70b766..a8b9187 100644
--- a/src/hb-wasm-shape.cc
+++ b/src/hb-wasm-shape.cc
@@ -240,7 +240,7 @@
     goto fail;
   }
 
-  func = wasm_runtime_lookup_function (module_inst, "shape_plan_create", nullptr);
+  func = wasm_runtime_lookup_function (module_inst, "shape_plan_create");
   if (func)
   {
     wasm_val_t results[1];
@@ -297,7 +297,7 @@
   if (plan->wasm_shape_planptr)
   {
 
-    auto *func = wasm_runtime_lookup_function (module_inst, "shape_plan_destroy", nullptr);
+    auto *func = wasm_runtime_lookup_function (module_inst, "shape_plan_destroy");
     if (func)
     {
       wasm_val_t arguments[1];
@@ -395,7 +395,7 @@
     goto fail;
   }
 
-  func = wasm_runtime_lookup_function (module_inst, "shape", nullptr);
+  func = wasm_runtime_lookup_function (module_inst, "shape");
   if (unlikely (!func))
   {
     DEBUG_MSG (WASM, module_inst, "Shape function not found.");
diff --git a/src/hb.hh b/src/hb.hh
index 972608d..0ceeb99 100644
--- a/src/hb.hh
+++ b/src/hb.hh
@@ -64,6 +64,7 @@
 #pragma GCC diagnostic error   "-Wbitwise-instead-of-logical"
 #pragma GCC diagnostic error   "-Wcast-align"
 #pragma GCC diagnostic error   "-Wcast-function-type"
+#pragma GCC diagnostic error   "-Wcast-function-type-strict"
 #pragma GCC diagnostic error   "-Wconstant-conversion"
 #pragma GCC diagnostic error   "-Wcomma"
 #pragma GCC diagnostic error   "-Wdelete-non-virtual-dtor"
@@ -177,6 +178,11 @@
 #define HB_EXTERN __declspec (dllexport) extern
 #endif
 
+// https://github.com/harfbuzz/harfbuzz/pull/4619
+#ifndef __STDC_FORMAT_MACROS
+#define __STDC_FORMAT_MACROS 1
+#endif
+
 #include "hb.h"
 #define HB_H_IN
 #include "hb-ot.h"
@@ -212,6 +218,12 @@
 #include <winapifamily.h>
 #endif
 
+#ifndef PRId32
+# define PRId32 "d"
+# define PRIu32 "u"
+# define PRIx32 "x"
+#endif
+
 #define HB_PASTE1(a,b) a##b
 #define HB_PASTE(a,b) HB_PASTE1(a,b)
 
diff --git a/src/meson.build b/src/meson.build
index 5401e5d..8e4cea6 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -371,6 +371,8 @@
   'hb-subset-cff2.cc',
   'hb-subset-input.cc',
   'hb-subset-input.hh',
+  'hb-subset-instancer-iup.hh',
+  'hb-subset-instancer-iup.cc',
   'hb-subset-instancer-solver.hh',
   'hb-subset-instancer-solver.cc',
   'hb-subset-plan.cc',
@@ -680,34 +682,21 @@
 endif
 
 if get_option('tests').enabled()
-  # TODO: MSVC gives the following,
+  # TODO: Microsoft LINK gives the following because extern, non dllexport
+  # symbols can only be used when linking against a static library
   # error LNK2019: unresolved external symbol "unsigned __int64 const * const _hb_NullPool"
   if cpp.get_define('_MSC_FULL_VER') == ''
     noinst_programs = {
       'main': 'main.cc',
-      'test-algs': ['test-algs.cc', 'hb-static.cc'],
       'test-basics': 'test.cc',
-      'test-bimap': ['test-bimap.cc', 'hb-static.cc'],
       'test-buffer-serialize': 'test-buffer-serialize.cc',
-      'test-classdef-graph': ['graph/test-classdef-graph.cc', 'hb-static.cc', 'graph/gsubgpos-context.cc'],
-      'test-instancer-solver': ['test-subset-instancer-solver.cc', 'hb-subset-instancer-solver.cc', 'hb-static.cc'],
-      'test-iter': ['test-iter.cc', 'hb-static.cc'],
-      'test-map': ['test-map.cc', 'hb-static.cc'],
-      'test-multimap': ['test-multimap.cc', 'hb-static.cc'],
       'test-ot-meta': 'test-ot-meta.cc',
       'test-ot-name': 'test-ot-name.cc',
       'test-ot-glyphname': 'test-ot-glyphname.cc',
       'test-ot-gpos-size-params': 'test-gpos-size-params.cc',
       'test-ot-gsub-get-alternates': 'test-gsub-get-alternates.cc',
       'test-ot-gsub-would-substitute': 'test-gsub-would-substitute.cc',
-      'test-priority-queue': ['test-priority-queue.cc', 'hb-static.cc'],
-      'test-repacker': ['test-repacker.cc', 'hb-static.cc', 'graph/gsubgpos-context.cc'],
-      'test-serialize': ['test-serialize.cc', 'hb-static.cc'],
-      'test-set': ['test-set.cc', 'hb-static.cc'],
-      'test-tuple-varstore': ['test-tuple-varstore.cc', 'hb-subset-instancer-solver.cc', 'hb-static.cc'],
-      'test-item-varstore': ['test-item-varstore.cc', 'hb-subset-instancer-solver.cc', 'hb-static.cc'],
       'test-use-table': 'test-use-table.cc',
-      'test-vector': ['test-vector.cc', 'hb-static.cc'],
     }
     foreach name, source : noinst_programs
       executable(name, source,
@@ -720,15 +709,30 @@
   endif
 
   compiled_tests = {
+    'test-algs': ['test-algs.cc', 'hb-static.cc'],
     'test-array': ['test-array.cc'],
+    'test-bimap': ['test-bimap.cc', 'hb-static.cc'],
+    'test-cff': ['test-cff.cc', 'hb-static.cc'],
+    'test-classdef-graph': ['graph/test-classdef-graph.cc', 'hb-static.cc', 'graph/gsubgpos-context.cc'],
+    'test-iter': ['test-iter.cc', 'hb-static.cc'],
     'test-machinery': ['test-machinery.cc', 'hb-static.cc'],
+    'test-map': ['test-map.cc', 'hb-static.cc'],
+    'test-multimap': ['test-multimap.cc', 'hb-static.cc'],
     'test-number': ['test-number.cc', 'hb-number.cc'],
     'test-ot-tag': ['hb-ot-tag.cc'],
+    'test-set': ['test-set.cc', 'hb-static.cc'],
+    'test-serialize': ['test-serialize.cc', 'hb-static.cc'],
+    'test-vector': ['test-vector.cc', 'hb-static.cc'],
+    'test-repacker': ['test-repacker.cc', 'hb-static.cc', 'graph/gsubgpos-context.cc'],
+    'test-instancer-solver': ['test-subset-instancer-solver.cc', 'hb-subset-instancer-solver.cc', 'hb-static.cc'],
+    'test-priority-queue': ['test-priority-queue.cc', 'hb-static.cc'],
+    'test-tuple-varstore': ['test-tuple-varstore.cc', 'hb-subset-instancer-solver.cc', 'hb-subset-instancer-iup.cc', 'hb-static.cc'],
+    'test-item-varstore': ['test-item-varstore.cc', 'hb-subset-instancer-solver.cc', 'hb-subset-instancer-iup.cc', 'hb-static.cc'],
     'test-unicode-ranges': ['test-unicode-ranges.cc'],
   }
   foreach name, source : compiled_tests
-    if cpp.get_argument_syntax() == 'msvc' and source.contains('hb-static.cc')
-      # TODO: MSVC doesn't like tests having hb-static.cc, fix them
+    if cpp.get_define('_MSC_FULL_VER') != '' and source.contains('hb-static.cc')
+      # TODO: Microsoft compilers cannot link tests using hb-static.cc, fix them
       continue
     endif
     test(name, executable(name, source,
@@ -868,7 +872,7 @@
   cmake_config.set('HB_LIB_SUFFIX', '${CMAKE_STATIC_LIBRARY_SUFFIX}')
 elif host_machine.system() == 'darwin'
   cmake_config.set('HB_LIB_PREFIX', '${CMAKE_SHARED_LIBRARY_PREFIX}')
-  cmake_config.set('HB_LIB_SUFFIX', '.@0@.${CMAKE_SHARED_LIBRARY_SUFFIX}'.format(hb_so_version))
+  cmake_config.set('HB_LIB_SUFFIX', '.@0@${CMAKE_SHARED_LIBRARY_SUFFIX}'.format(hb_so_version))
 elif host_machine.system() == 'windows'
   cmake_config.set('HB_LIB_PREFIX', '${CMAKE_IMPORT_LIBRARY_PREFIX}')
   cmake_config.set('HB_LIB_SUFFIX', '${CMAKE_IMPORT_LIBRARY_SUFFIX}')
diff --git a/src/relative_to.py b/src/relative_to.py
index 8a676bf..b660d27 100755
--- a/src/relative_to.py
+++ b/src/relative_to.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python3
+#!/usr/bin/env python3
 
 import sys
 from os import path
diff --git a/src/test-cff.cc b/src/test-cff.cc
new file mode 100644
index 0000000..38ddba3
--- /dev/null
+++ b/src/test-cff.cc
@@ -0,0 +1,75 @@
+/*
+ * Copyright © 2024  David Corbett
+ *
+ *  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.
+ */
+
+#include "hb.hh"
+#include "hb-ot-cff-common.hh"
+#include "hb-subset-cff-common.hh"
+
+int
+main (int argc, char **argv)
+{
+  /* Test encode_num_tp */
+  {
+    CFF::str_buff_t buff;
+    CFF::str_encoder_t encoder (buff);
+    CFF::number_t number;
+    struct num_tp_test {
+      double input;
+      unsigned length;
+      unsigned char output[7];
+    };
+    struct num_tp_test num_tp_tests[] = {
+      { -9.399999999999999, 4, { 0x1E, 0xE9, 0xA4, 0xFF } }, // -9.4
+      { 9.399999999999999999, 3, { 0x1E, 0x9A, 0x4F } }, // 9.4
+      { 456.8, 4, { 0x1E, 0x45, 0x6A, 0x8F } }, // 456.8
+      { 98765.37e2, 5, { 0x1E, 0x98, 0x76, 0x53, 0x7F } }, // 9876537
+      { 1234567890.0, 7, { 0x1E, 0x12, 0x34, 0x56, 0x79, 0xB2, 0xFF } }, // 12345679E2
+      { 9.876537e-4, 7, { 0x1E, 0x98, 0x76, 0x53, 0x7C, 0x10, 0xFF } }, // 9876537E-10
+      { 9.876537e4, 6, { 0x1E, 0x98, 0x76, 0x5A, 0x37, 0xFF } }, // 98765.37
+      { 1e8, 3, { 0x1E, 0x1B, 0x8F } }, // 1E8
+      { 1e-5, 3, { 0x1E, 0x1C, 0x5F } }, // 1E-5
+      { 1.2e8, 4, { 0x1E, 0x12, 0xB7, 0xFF } }, // 12E7
+      { 1.2345e-5, 5, { 0x1E, 0x12, 0x34, 0x5C, 0x9F } }, // 12345E-9
+      { 9.0987654e8, 6, { 0x1E, 0x90, 0x98, 0x76, 0x54, 0x0F } }, // 909876540
+      { 0.1, 3, { 0x1E, 0xA1, 0xFF } }, // .1
+      { -0.1, 3, { 0x1E, 0xEA, 0x1F } }, // -.1
+      { 0.01, 3, { 0x1E, 0x1C, 0x2F } }, // 1E-2
+      { -0.01, 4, { 0x1E, 0xE1, 0xC2, 0xFF } }, // -1E-2
+      { 0.0123, 4, { 0x1E, 0x12, 0x3C, 0x4F } }, // 123E-4
+      { -0.0123, 5, { 0x1E, 0xE1, 0x23, 0xC4, 0xFF } }, // -123E-4
+    };
+    for (size_t t = 0; t < sizeof num_tp_tests / sizeof num_tp_tests[0]; t++)
+    {
+      struct num_tp_test num_tp_test = num_tp_tests[t];
+      number.set_real (num_tp_test.input);
+      encoder.encode_num_tp (number);
+      assert (buff.length == num_tp_test.length);
+      for (unsigned i = 0; i < buff.length; i++)
+	assert (buff[i] == num_tp_test.output[i]);
+      encoder.reset ();
+    }
+  }
+
+  return 0;
+}
diff --git a/src/test-item-varstore.cc b/src/test-item-varstore.cc
index 3e0875e..bf0a100 100644
--- a/src/test-item-varstore.cc
+++ b/src/test-item-varstore.cc
@@ -40,17 +40,17 @@
   axis_idx_tag_map.set (1, axis_tag);
 
   OT::item_variations_t item_vars;
-  const OT::VariationStore& src_var_store = hvar_table+(hvar_table->varStore);
+  const OT::ItemVariationStore& src_var_store = hvar_table+(hvar_table->varStore);
   bool result = item_vars.create_from_item_varstore (src_var_store, axis_idx_tag_map);
       
   assert (result);
 
   /* partial instancing wght=300:800 */
   hb_hashmap_t<hb_tag_t, Triple> normalized_axes_location;
-  normalized_axes_location.set (axis_tag, Triple (-0.512817f, 0.f, 0.700012f));
+  normalized_axes_location.set (axis_tag, Triple (-0.512817, 0.0, 0.7000120));
 
   hb_hashmap_t<hb_tag_t, TripleDistances> axes_triple_distances;
-  axes_triple_distances.set (axis_tag, TripleDistances (200.f, 500.f));
+  axes_triple_distances.set (axis_tag, TripleDistances (200.0, 500.0));
 
   result = item_vars.instantiate_tuple_vars (normalized_axes_location, axes_triple_distances);
   assert (result);
diff --git a/src/test-repacker.cc b/src/test-repacker.cc
index 950e7d2..7f89fbf 100644
--- a/src/test-repacker.cc
+++ b/src/test-repacker.cc
@@ -433,16 +433,13 @@
   }
 };
 
-
-
-
-
 static void run_resolve_overflow_test (const char* name,
                                        hb_serialize_context_t& overflowing,
                                        hb_serialize_context_t& expected,
                                        unsigned num_iterations = 0,
                                        bool recalculate_extensions = false,
-                                       hb_tag_t tag = HB_TAG ('G', 'S', 'U', 'B'))
+                                       hb_tag_t tag = HB_TAG ('G', 'S', 'U', 'B'),
+                                       bool check_binary_equivalence = false)
 {
   printf (">>> Testing overflowing resolution for %s\n",
           name);
@@ -452,6 +449,10 @@
   graph_t expected_graph (expected.object_graph ());
   if (graph::will_overflow (expected_graph))
   {
+    if (check_binary_equivalence) {
+      printf("when binary equivalence checking is enabled, the expected graph cannot overflow.");
+      assert(!check_binary_equivalence);
+    }
     expected_graph.assign_spaces ();
     expected_graph.sort_shortest_distance ();
   }
@@ -464,12 +465,27 @@
                                       graph));
 
   // Check the graphs can be serialized.
-  hb_blob_t* out = graph::serialize (graph);
-  assert (out);
-  hb_blob_destroy (out);
-  out = graph::serialize (expected_graph);
-  assert (out);
-  hb_blob_destroy (out);
+  hb_blob_t* out1 = graph::serialize (graph);
+  assert (out1);
+  hb_blob_t* out2 = graph::serialize (expected_graph);
+  assert (out2);
+  if (check_binary_equivalence) {
+    unsigned l1, l2;
+    const char* d1 = hb_blob_get_data(out1, &l1);
+    const char* d2 = hb_blob_get_data(out2, &l2);
+
+    bool match = (l1 == l2) && (memcmp(d1, d2, l1) == 0);
+    if (!match) {
+      printf("## Result:\n");
+      graph.print();
+      printf("## Expected:\n");
+      expected_graph.print();
+      assert(match);
+    }
+  }
+
+  hb_blob_destroy (out1);
+  hb_blob_destroy (out2);
 
   // Check the graphs are equivalent
   graph.normalize ();
@@ -597,6 +613,31 @@
 }
 
 static void
+populate_serializer_with_multiple_dedup_overflow (hb_serialize_context_t* c)
+{
+  std::string large_string(70000, 'a');
+  c->start_serialize<char> ();
+
+  unsigned leaf = add_object("def", 3, c);
+
+  constexpr unsigned num_mid_nodes = 20;
+  unsigned mid_nodes[num_mid_nodes];
+  for (unsigned i = 0; i < num_mid_nodes; i++) {
+    start_object(large_string.c_str(), 10000 + i, c);
+    add_offset(leaf, c);
+    mid_nodes[i] = c->pop_pack(false);
+  }
+
+  start_object("abc", 3, c);
+  for (unsigned i = 0; i < num_mid_nodes; i++) {
+    add_wide_offset(mid_nodes[i], c);
+  }
+  c->pop_pack(false);
+
+  c->end_serialize();
+}
+
+static void
 populate_serializer_with_isolation_overflow (hb_serialize_context_t* c)
 {
   std::string large_string(70000, 'a');
@@ -755,6 +796,54 @@
 }
 
 static void
+populate_serializer_with_repack_last (hb_serialize_context_t* c, bool with_overflow)
+{
+  std::string large_string(70000, 'c');
+  c->start_serialize<char> ();
+  c->push();
+
+  // Obj E
+  unsigned obj_e_1, obj_e_2;
+  if (with_overflow) {
+    obj_e_1 = add_object("a", 1, c);
+    obj_e_2 = obj_e_1;
+  } else {
+    obj_e_2 = add_object("a", 1, c);
+  }
+
+  // Obj D
+  c->push();
+  add_offset(obj_e_2, c);
+  extend(large_string.c_str(), 30000, c);
+  unsigned obj_d = c->pop_pack(false);
+
+  add_offset(obj_d, c);
+  assert(c->last_added_child_index() == obj_d);
+
+  if (!with_overflow) {
+    obj_e_1 = add_object("a", 1, c);
+  }
+
+  // Obj C
+  c->push();
+  add_offset(obj_e_1, c);
+  extend(large_string.c_str(), 40000, c);
+  unsigned obj_c = c->pop_pack(false);
+
+  add_offset(obj_c, c);
+
+  // Obj B
+  unsigned obj_b = add_object("b", 1, c);
+  add_offset(obj_b, c);
+
+  // Obj A
+  c->repack_last(obj_d);
+  c->pop_pack(false);
+
+  c->end_serialize();
+}
+
+static void
 populate_serializer_spaces (hb_serialize_context_t* c, bool with_overflow)
 {
   std::string large_string(70000, 'a');
@@ -1682,6 +1771,21 @@
   hb_blob_destroy (out);
 }
 
+static void test_resolve_overflows_via_multiple_duplications ()
+{
+  size_t buffer_size = 300000;
+  void* buffer = malloc (buffer_size);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_with_multiple_dedup_overflow (&c);
+  graph_t graph (c.object_graph ());
+
+  hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG_NONE, 5);
+  assert (out);
+
+  free (buffer);
+  hb_blob_destroy (out);
+}
+
 static void test_resolve_overflows_via_space_assignment ()
 {
   size_t buffer_size = 160000;
@@ -1946,12 +2050,12 @@
   void* buffer = malloc (buffer_size);
   assert (buffer);
   hb_serialize_context_t c (buffer, buffer_size);
-  populate_serializer_with_large_pair_pos_2 <1, 1596, 10>(&c, true, false, false);
+  populate_serializer_with_large_pair_pos_2 <1, 1636, 10>(&c, true, false, false);
 
   void* expected_buffer = malloc (buffer_size);
   assert (expected_buffer);
   hb_serialize_context_t e (expected_buffer, buffer_size);
-  populate_serializer_with_large_pair_pos_2 <2, 798, 10>(&e, true, false, false);
+  populate_serializer_with_large_pair_pos_2 <2, 818, 10>(&e, true, false, false);
 
   run_resolve_overflow_test ("test_resolve_with_close_to_limit_pair_pos_2_split",
                              c,
@@ -2127,6 +2231,31 @@
   free(buffer);
 }
 
+static void
+test_repack_last ()
+{
+  size_t buffer_size = 200000;
+  void* buffer = malloc (buffer_size);
+  assert (buffer);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_with_repack_last (&c, true);
+
+  void* expected_buffer = malloc (buffer_size);
+  assert (expected_buffer);
+  hb_serialize_context_t e (expected_buffer, buffer_size);
+  populate_serializer_with_repack_last (&e, false);
+
+  run_resolve_overflow_test ("test_repack_last",
+                             c,
+                             e,
+                             20,
+                             false,
+                             HB_TAG('a', 'b', 'c', 'd'),
+                             true);
+
+  free (buffer);
+  free (expected_buffer);
+}
 
 // TODO(garretrieger): update will_overflow tests to check the overflows array.
 // TODO(garretrieger): add tests for priority raising.
@@ -2141,6 +2270,7 @@
   test_will_overflow_3 ();
   test_resolve_overflows_via_sort ();
   test_resolve_overflows_via_duplication ();
+  test_resolve_overflows_via_multiple_duplications ();
   test_resolve_overflows_via_priority ();
   test_resolve_overflows_via_space_assignment ();
   test_resolve_overflows_via_isolation ();
@@ -2154,6 +2284,7 @@
   test_duplicate_leaf ();
   test_duplicate_interior ();
   test_virtual_link ();
+  test_repack_last();
   test_shared_node_with_virtual_links ();
   test_resolve_with_extension_promotion ();
   test_resolve_with_shared_extension_promotion ();
diff --git a/src/test-subset-instancer-solver.cc b/src/test-subset-instancer-solver.cc
index e8294cf..06b71bd 100644
--- a/src/test-subset-instancer-solver.cc
+++ b/src/test-subset-instancer-solver.cc
@@ -24,392 +24,408 @@
  * Google Author(s): Qunxin Liu
  */
 
+#include <math.h>
 #include "hb-subset-instancer-solver.hh"
 
 static inline bool approx (Triple a, Triple b)
 {
-  return fabsf (a.minimum - b.minimum) < 0.000001f &&
-         fabsf (a.middle - b.middle) < 0.000001f &&
-         fabsf (a.maximum - b.maximum) < 0.000001f;
+  return abs (a.minimum - b.minimum) < 0.000001 &&
+         abs (a.middle - b.middle) < 0.000001 &&
+         abs (a.maximum - b.maximum) < 0.000001;
 }
 
-static inline bool approx (float a, float b)
-{ return fabsf (a - b) < 0.000001f; }
+static inline bool approx (double a, double b)
+{ return abs (a - b) < 0.000001; }
 
 /* tests ported from
  * https://github.com/fonttools/fonttools/blob/main/Tests/varLib/instancer/solver_test.py */
 int
 main (int argc, char **argv)
 {
-  TripleDistances default_axis_distances{1.f, 1.f};
+  TripleDistances default_axis_distances{1.0, 1.0};
   /* Case 1 */
   {
     /* pin axis*/
-    Triple tent (0.f, 1.f, 1.f);
-    Triple axis_range (0.f, 0.f, 0.f);
-    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    Triple tent (0.0, 1.0, 1.0);
+    Triple axis_range (0.0, 0.0, 0.0);
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
     assert (out.length == 0);
   }
 
   {
     /* pin axis*/
-    Triple tent (0.f, 1.f, 1.f);
-    Triple axis_range (0.5f, 0.5f, 0.5f);
-    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    Triple tent (0.0, 1.0, 1.0);
+    Triple axis_range (0.5, 0.5, 0.5);
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
     assert (out.length == 1);
-    assert (out[0].first == 0.5f);
+    assert (out[0].first == 0.5);
     assert (out[0].second == Triple ());
   }
 
   {
     /* tent falls outside the new axis range */
-    Triple tent (0.3f, 0.5f, 0.8f);
-    Triple axis_range (0.1f, 0.2f, 0.3f);
-    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    Triple tent (0.3, 0.5, 0.8);
+    Triple axis_range (0.1, 0.2, 0.3);
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
     assert (out.length == 0);
   }
 
   /* Case 2 */
   {
-    Triple tent (0.f, 1.f, 1.f);
-    Triple axis_range (-1.f, 0.f, 0.5f);
-    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    Triple tent (0.0, 1.0, 1.0);
+    Triple axis_range (-1.0, 0.0, 0.5);
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
     assert (out.length == 1);
-    assert (out[0].first == 0.5f);
-    assert (out[0].second == Triple (0.f, 1.f, 1.f));
+    assert (out[0].first == 0.5);
+    assert (out[0].second == Triple (0.0, 1.0, 1.0));
   }
 
   /* Case 2 */
   {
-    Triple tent (0.f, 1.f, 1.f);
-    Triple axis_range (-1.f, 0.f, 0.75f);
-    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    Triple tent (0.0, 1.0, 1.0);
+    Triple axis_range (-1.0, 0.0, 0.75);
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
     assert (out.length == 1);
-    assert (out[0].first == 0.75f);
-    assert (out[0].second == Triple (0.f, 1.f, 1.f));
+    assert (out[0].first == 0.75);
+    assert (out[0].second == Triple (0.0, 1.0, 1.0));
   }
 
   /* Without gain: */
   /* Case 3 */
   {
-    Triple tent (0.f, 0.2f, 1.f);
-    Triple axis_range (-1.f, 0.f, 0.8f);
-    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
-    assert (out.length == 1);
-    assert (out[0].first == 1.f);
-    assert (out[0].second == Triple (0.f, 0.25f, 1.25f));
+    Triple tent (0.0, 0.2, 1.0);
+    Triple axis_range (-1.0, 0.0, 0.8);
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 2);
+    assert (out[0].first == 1.0);
+    assert (out[0].second == Triple (0.0, 0.25, 1.0));
+    assert (approx (out[1].first, 0.250));
+    assert (out[1].second == Triple (0.25, 1.0, 1.0));
   }
 
   /* Case 3 boundary */
   {
-    Triple tent (0.f, 0.4f, 1.f);
-    Triple axis_range (-1.f, 0.f, 0.5f);
-    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
-    assert (out.length == 1);
-    assert (out[0].first == 1.f);
-    assert (out[0].second == Triple (0.f, 0.8f, 32767/(float) (1 << 14)));
+    Triple tent (0.0, 0.4, 1.0);
+    Triple axis_range (-1.0, 0.0, 0.5);
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 2);
+    assert (out[0].first == 1.0);
+    assert (out[0].second == Triple (0.0, 0.8, 1.0));
+    assert (approx (out[1].first, 2.5/3));
+    assert (out[1].second == Triple (0.8, 1.0, 1.0));
   }
 
   /* Case 4 */
   {
-    Triple tent (0.f, 0.25f, 1.f);
-    Triple axis_range (-1.f, 0.f, 0.4f);
-    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    Triple tent (0.0, 0.25, 1.0);
+    Triple axis_range (-1.0, 0.0, 0.4);
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
     assert (out.length == 2);
-    assert (out[0].first == 1.f);
-    assert (out[0].second == Triple (0.f, 0.625f, 1.f));
-    assert (approx (out[1].first, 0.8f));
-    assert (out[1].second == Triple (0.625f, 1.f, 1.f));
+    assert (out[0].first == 1.0);
+    assert (out[0].second == Triple (0.0, 0.625, 1.0));
+    assert (approx (out[1].first, 0.80));
+    assert (out[1].second == Triple (0.625, 1.0, 1.0));
   }
 
   /* Case 4 */
   {
-    Triple tent (0.25f, 0.3f, 1.05f);
-    Triple axis_range (0.f, 0.2f, 0.4f);
-    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    Triple tent (0.25, 0.3, 1.05);
+    Triple axis_range (0.0, 0.2, 0.4);
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
     assert (out.length == 2);
-    assert (out[0].first == 1.f);
-    assert (approx (out[0].second, Triple (0.25f, 0.5f, 1.f)));
-    assert (approx (out[1].first, 2.6f/3));
-    assert (approx (out[1].second, Triple (0.5f, 1.f, 1.f)));
+    assert (out[0].first == 1.0);
+    assert (approx (out[0].second, Triple (0.25, 0.5, 1.0)));
+    assert (approx (out[1].first, 2.6 / 3));
+    assert (approx (out[1].second, Triple (0.5, 1.0, 1.0)));
   }
 
   /* Case 4 boundary */
   {
-    Triple tent (0.25f, 0.5f, 1.f);
-    Triple axis_range (0.f, 0.25f, 0.5f);
-    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    Triple tent (0.25, 0.5, 1.0);
+    Triple axis_range (0.0, 0.25, 0.5);
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
     assert (out.length == 1);
-    assert (out[0].first == 1.f);
-    assert (out[0].second == Triple (0.f, 1.f, 1.f));
+    assert (out[0].first == 1.0);
+    assert (out[0].second == Triple (0.0, 1.0, 1.0));
   }
 
   /* With gain */
   /* Case 3a/1neg */
   {
-    Triple tent (0.f, 0.5f, 1.f);
-    Triple axis_range (0.f, 0.5f, 1.f);
-    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    Triple tent (0.0, 0.5, 1.0);
+    Triple axis_range (0.0, 0.5, 1.0);
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
     assert (out.length == 3);
-    assert (out[0].first == 1.f);
+    assert (out[0].first == 1.0);
     assert (out[0].second == Triple ());
-    assert (out[1].first == -1.f);
-    assert (out[1].second == Triple (0.f, 1.f, 1.f));
-    assert (out[2].first == -1.f);
-    assert (out[2].second == Triple (-1.f, -1.f, 0.f));
+    assert (out[1].first == -1.0);
+    assert (out[1].second == Triple (0.0, 1.0, 1.0));
+    assert (out[2].first == -1.0);
+    assert (out[2].second == Triple (-1.0, -1.0, 0.0));
   }
 
   {
-    Triple tent (0.f, 0.5f, 1.f);
-    Triple axis_range (0.f, 0.5f, 0.75f);
-    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    Triple tent (0.0, 0.5, 1.0);
+    Triple axis_range (0.0, 0.5, 0.75);
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
     assert (out.length == 3);
-    assert (out[0].first == 1.f);
+    assert (out[0].first == 1.0);
     assert (out[0].second == Triple ());
-    assert (out[1].first == -0.5f);
-    assert (out[1].second == Triple (0.f, 1.f, 1.f));
-    assert (out[2].first == -1.f);
-    assert (out[2].second == Triple (-1.f, -1.f, 0.f));
+    assert (out[1].first == -0.5);
+    assert (out[1].second == Triple (0.0, 1.0, 1.0));
+    assert (out[2].first == -1.0);
+    assert (out[2].second == Triple (-1.0, -1.0, 0.0));
   }
 
   {
-    Triple tent (0.f, 0.5f, 1.f);
-    Triple axis_range (0.f, 0.25f, 0.8f);
-    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    Triple tent (0.0, 0.50, 1.0);
+    Triple axis_range (0.0, 0.25, 0.8);
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
     assert (out.length == 4);
-    assert (out[0].first == 0.5f);
+    assert (out[0].first == 0.5);
     assert (out[0].second == Triple ());
-    assert (out[1].first == 0.5f);
-    assert (approx (out[1].second, Triple (0.f, 0.454545f, 0.909091f)));
-    assert (approx (out[2].first, -0.1f));
-    assert (approx (out[2].second, Triple (0.909091f, 1.f, 1.f)));
-    assert (out[3].first == -0.5f);
-    assert (out[3].second == Triple (-1.f, -1.f, 0.f));
+    assert (out[1].first == 0.5);
+    assert (approx (out[1].second, Triple (0.0, 0.454545, 0.909091)));
+    assert (approx (out[2].first, -0.1));
+    assert (approx (out[2].second, Triple (0.909091, 1.0, 1.0)));
+    assert (out[3].first == -0.5);
+    assert (out[3].second == Triple (-1.0, -1.0, 0.0));
   }
 
   /* Case 3a/1neg */
   {
-    Triple tent (0.f, 0.5f, 2.f);
-    Triple axis_range (0.2f, 0.5f, 0.8f);
-    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    Triple tent (0.0, 0.5, 2.0);
+    Triple axis_range (0.2, 0.5, 0.8);
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
     assert (out.length == 3);
-    assert (out[0].first == 1.f);
+    assert (out[0].first == 1.0);
     assert (out[0].second == Triple ());
-    assert (approx (out[1].first, -0.2f));
-    assert (out[1].second == Triple (0.f, 1.f, 1.f));
-    assert (approx (out[2].first, -0.6f));
-    assert (out[2].second == Triple (-1.f, -1.f, 0.f));
+    assert (approx (out[1].first, -0.2));
+    assert (out[1].second == Triple (0.0, 1.0, 1.0));
+    assert (approx (out[2].first, -0.6));
+    assert (out[2].second == Triple (-1.0, -1.0, 0.0));
   }
 
   /* Case 3a/1neg */
   {
-    Triple tent (0.f, 0.5f, 2.f);
-    Triple axis_range (0.2f, 0.5f, 1.f);
-    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    Triple tent (0.0, 0.5, 2.0);
+    Triple axis_range (0.2, 0.5, 1.0);
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
     assert (out.length == 3);
-    assert (out[0].first == 1.f);
+    assert (out[0].first == 1.0);
     assert (out[0].second == Triple ());
-    assert (approx (out[1].first, -1.f/3));
-    assert (out[1].second == Triple (0.f, 1.f, 1.f));
-    assert (approx (out[2].first, -0.6f));
-    assert (out[2].second == Triple (-1.f, -1.f, 0.f));
+    assert (approx (out[1].first, -1.0/3));
+    assert (out[1].second == Triple (0.0, 1.0, 1.0));
+    assert (approx (out[2].first, -0.6));
+    assert (out[2].second == Triple (-1.0, -1.0, 0.0));
   }
 
   /* Case 3 */
   {
-    Triple tent (0.f, 0.5f, 1.f);
-    Triple axis_range (0.25f, 0.25f, 0.75f);
-    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    Triple tent (0.0, 0.5, 1.0);
+    Triple axis_range (0.25, 0.25, 0.75);
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
     assert (out.length == 2);
-    assert (out[0].first == 0.5f);
+    assert (out[0].first == 0.5);
     assert (out[0].second == Triple ());
-    assert (out[1].first == 0.5f);
-    assert (out[1].second == Triple (0.f, 0.5f, 1.0f));
+    assert (out[1].first == 0.5);
+    assert (out[1].second == Triple (0.0, 0.5, 1.0));
   }
 
   /* Case 1neg */
   {
-    Triple tent (0.f, 0.5f, 1.f);
-    Triple axis_range (0.f, 0.25f, 0.5f);
-    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    Triple tent (0.0, 0.5, 1.0);
+    Triple axis_range (0.0, 0.25, 0.5);
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
     assert (out.length == 3);
-    assert (out[0].first == 0.5f);
+    assert (out[0].first == 0.5);
     assert (out[0].second == Triple ());
-    assert (out[1].first == 0.5f);
-    assert (out[1].second == Triple (0.f, 1.f, 1.f));
-    assert (out[2].first == -0.5f);
-    assert (out[2].second == Triple (-1.f, -1.f, 0.f));
+    assert (out[1].first == 0.5);
+    assert (out[1].second == Triple (0.0, 1.0, 1.0));
+    assert (out[2].first == -0.5);
+    assert (out[2].second == Triple (-1.0, -1.0, 0.0));
   }
 
   /* Case 2neg */
   {
-    Triple tent (0.05f, 0.55f, 1.f);
-    Triple axis_range (0.f, 0.25f, 0.5f);
-    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    Triple tent (0.05, 0.55, 1.0);
+    Triple axis_range (0.0, 0.25, 0.5);
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
     assert (out.length == 4);
-    assert (approx (out[0].first, 0.4f));
+    assert (approx (out[0].first, 0.4));
     assert (out[0].second == Triple ());
-    assert (approx (out[1].first, 0.5f));
-    assert (out[1].second == Triple (0.f, 1.f, 1.f));
-    assert (approx (out[2].first, -0.4f));
-    assert (out[2].second == Triple (-1.f, -0.8f, 0.f));
-    assert (approx (out[3].first, -0.4f));
-    assert (out[3].second == Triple (-1.f, -1.f, -0.8f));
+    assert (approx (out[1].first, 0.5));
+    assert (out[1].second == Triple (0.0, 1.0, 1.0));
+    assert (approx (out[2].first, -0.4));
+    assert (out[2].second == Triple (-1.0, -0.8, 0.0));
+    assert (approx (out[3].first, -0.4));
+    assert (out[3].second == Triple (-1.0, -1.0, -0.8));
   }
 
   /* Case 2neg, other side */
   {
-    Triple tent (-1.f, -0.55f, -0.05f);
-    Triple axis_range (-0.5f, -0.25f, 0.f);
-    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    Triple tent (-1.0, -0.55, -0.05);
+    Triple axis_range (-0.5, -0.25, 0.0);
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
     assert (out.length == 4);
-    assert (approx (out[0].first, 0.4f));
+    assert (approx (out[0].first, 0.4));
     assert (out[0].second == Triple ());
-    assert (approx (out[1].first, 0.5f));
-    assert (out[1].second == Triple (-1.f, -1.f, 0.f));
-    assert (approx (out[2].first, -0.4f));
-    assert (out[2].second == Triple (0.f, 0.8f, 1.f));
-    assert (approx (out[3].first, -0.4f));
-    assert (out[3].second == Triple (0.8f, 1.f, 1.f));
+    assert (approx (out[1].first, 0.5));
+    assert (out[1].second == Triple (-1.0, -1.0, 0.0));
+    assert (approx (out[2].first, -0.4));
+    assert (out[2].second == Triple (0.0, 0.8, 1.0));
+    assert (approx (out[3].first, -0.4));
+    assert (out[3].second == Triple (0.8, 1.0, 1.0));
   }
 
   /* Misc corner cases */
   {
-    Triple tent (0.5f, 0.5f, 0.5f);
-    Triple axis_range (0.5f, 0.5f, 0.5f);
-    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    Triple tent (0.5, 0.5, 0.5);
+    Triple axis_range (0.5, 0.5, 0.5);
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
     assert (out.length == 1);
-    assert (out[0].first == 1.f);
+    assert (out[0].first == 1.0);
     assert (out[0].second == Triple ());
   }
 
   {
-    Triple tent (0.3f, 0.5f, 0.7f);
-    Triple axis_range (0.1f, 0.5f, 0.9f);
-    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    Triple tent (0.3, 0.5, 0.7);
+    Triple axis_range (0.1, 0.5, 0.9);
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
     assert (out.length == 5);
-    assert (out[0].first == 1.f);
+    assert (out[0].first == 1.0);
     assert (out[0].second == Triple ());
-    assert (out[1].first == -1.f);
-    assert (out[1].second == Triple (0.f, 0.5f, 1.f));
-    assert (out[2].first == -1.f);
-    assert (out[2].second == Triple (0.5f, 1.f, 1.f));
-    assert (out[3].first == -1.f);
-    assert (approx (out[3].second, Triple (-1.f, -0.5f, 0.f)));
-    assert (out[4].first == -1.f);
-    assert (approx (out[4].second, Triple (-1.f, -1.f, -0.5f)));
+    assert (out[1].first == -1.0);
+    assert (approx(out[1].second, Triple (0.0, 0.5, 1.0)));
+    assert (out[2].first == -1.0);
+    assert (approx(out[2].second, Triple (0.5, 1.0, 1.0)));
+    assert (out[3].first == -1.0);
+    assert (approx (out[3].second, Triple (-1.0, -0.5, 0.0)));
+    assert (out[4].first == -1.0);
+    assert (approx (out[4].second, Triple (-1.0, -1.0, -0.5)));
   }
 
   {
-    Triple tent (0.5f, 0.5f, 0.5f);
-    Triple axis_range (0.25f, 0.25f, 0.5f);
-    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    Triple tent (0.5, 0.5, 0.5);
+    Triple axis_range (0.25, 0.25, 0.5);
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
     assert (out.length == 1);
-    assert (out[0].first == 1.f);
-    assert (out[0].second == Triple (1.f, 1.f, 1.f));
+    assert (out[0].first == 1.0);
+    assert (out[0].second == Triple (1.0, 1.0, 1.0));
   }
 
   {
-    Triple tent (0.5f, 0.5f, 0.5f);
-    Triple axis_range (0.25f, 0.35f, 0.5f);
-    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    Triple tent (0.5, 0.5, 0.5);
+    Triple axis_range (0.25, 0.35, 0.5);
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
     assert (out.length == 1);
-    assert (out[0].first == 1.f);
-    assert (out[0].second == Triple (1.f, 1.f, 1.f));
+    assert (out[0].first == 1.0);
+    assert (out[0].second == Triple (1.0, 1.0, 1.0));
   }
 
   {
-    Triple tent (0.5f, 0.5f, 0.55f);
-    Triple axis_range (0.25f, 0.35f, 0.5f);
-    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    Triple tent (0.5, 0.5, 0.55);
+    Triple axis_range (0.25, 0.35, 0.5);
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
     assert (out.length == 1);
-    assert (out[0].first == 1.f);
-    assert (out[0].second == Triple (1.f, 1.f, 1.f));
+    assert (out[0].first == 1.0);
+    assert (out[0].second == Triple (1.0, 1.0, 1.0));
   }
 
   {
-    Triple tent (0.5f, 0.5f, 1.f);
-    Triple axis_range (0.5f, 0.5f, 1.f);
-    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    Triple tent (0.5, 0.5, 1.0);
+    Triple axis_range (0.5, 0.5, 1.0);
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
     assert (out.length == 2);
-    assert (out[0].first == 1.f);
+    assert (out[0].first == 1.0);
     assert (out[0].second == Triple ());
-    assert (out[1].first == -1.f);
-    assert (out[1].second == Triple (0.f, 1.f, 1.f));
+    assert (out[1].first == -1.0);
+    assert (out[1].second == Triple (0.0, 1.0, 1.0));
   }
 
   {
-    Triple tent (0.25f, 0.5f, 1.f);
-    Triple axis_range (0.5f, 0.5f, 1.f);
-    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    Triple tent (0.25, 0.5, 1.0);
+    Triple axis_range (0.5, 0.5, 1.0);
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
     assert (out.length == 2);
-    assert (out[0].first == 1.f);
+    assert (out[0].first == 1.0);
     assert (out[0].second == Triple ());
-    assert (out[1].first == -1.f);
-    assert (out[1].second == Triple (0.f, 1.f, 1.f));
+    assert (out[1].first == -1.0);
+    assert (out[1].second == Triple (0.0, 1.0, 1.0));
   }
 
   {
-    Triple tent (0.f, 0.2f, 1.f);
-    Triple axis_range (0.f, 0.f, 0.5f);
-    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
-    assert (out.length == 1);
-    assert (out[0].first == 1.f);
-    assert (out[0].second == Triple (0.f, 0.4f, 32767/(float) (1 << 14)));
+    Triple tent (0.0, 0.2, 1.0);
+    Triple axis_range (0.0, 0.0, 0.5);
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 2);
+    assert (out[0].first == 1.0);
+    assert (out[0].second == Triple (0.0, 0.4, 1.0));
+    assert (out[1].first == 0.625);
+    assert (out[1].second == Triple (0.4, 1.0, 1.0));
   }
 
 
   {
-    Triple tent (0.f, 0.5f, 1.f);
-    Triple axis_range (-1.f, 0.25f, 1.f);
-    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    Triple tent (0.0, 0.5, 1.0);
+    Triple axis_range (-1.0, 0.25, 1.0);
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
     assert (out.length == 5);
-    assert (out[0].first == 0.5f);
+    assert (out[0].first == 0.5);
     assert (out[0].second == Triple ());
-    assert (out[1].first == 0.5f);
-    assert (out[1].second == Triple (0.f, 1.f/3, 2.f/3));
-    assert (out[2].first == -0.5f);
-    assert (out[2].second == Triple (2.f/3, 1.f, 1.f));
-    assert (out[3].first == -0.5f);
-    assert (out[3].second == Triple (-1.f, -0.2f, 0.f));
-    assert (out[4].first == -0.5f);
-    assert (out[4].second == Triple (-1.f, -1.f, -0.2f));
+    assert (out[1].first == 0.5);
+    assert (out[1].second == Triple (0.0, 1.0/3, 2.0/3));
+    assert (out[2].first == -0.5);
+    assert (out[2].second == Triple (2.0/3, 1.0, 1.0));
+    assert (out[3].first == -0.5);
+    assert (out[3].second == Triple (-1.0, -0.2, 0.0));
+    assert (out[4].first == -0.5);
+    assert (out[4].second == Triple (-1.0, -1.0, -0.2));
   }
 
   {
-    Triple tent (0.5f, 0.5f, 0.5f);
-    Triple axis_range (0.f, 0.5f, 1.f);
-    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    Triple tent (0.5, 0.5, 0.5);
+    Triple axis_range (0.0, 0.5, 1.0);
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
     assert (out.length == 5);
-    assert (out[0].first == 1.f);
+    assert (out[0].first == 1.0);
     assert (out[0].second == Triple ());
-    assert (out[1].first == -1.f);
-    assert (out[1].second == Triple (0.f, 2/(float) (1 << 14), 1.f));
-    assert (out[2].first == -1.f);
-    assert (out[2].second == Triple (2/(float) (1 << 14), 1.f, 1.f));
-    assert (out[3].first == -1.f);
-    assert (out[3].second == Triple (-1.f, -2/(float) (1 << 14), 0.f));
-    assert (out[4].first == -1.f);
-    assert (out[4].second == Triple (-1.f, -1.f, -2/(float) (1 << 14)));
+    assert (out[1].first == -1.0);
+    assert (out[1].second == Triple (0.0, 2/(double) (1 << 14), 1.0));
+    assert (out[2].first == -1.0);
+    assert (out[2].second == Triple (2/(double) (1 << 14), 1.0, 1.0));
+    assert (out[3].first == -1.0);
+    assert (out[3].second == Triple (-1.0, -2/(double) (1 << 14), 0.0));
+    assert (out[4].first == -1.0);
+    assert (out[4].second == Triple (-1.0, -1.0, -2/(double) (1 << 14)));
   }
 
   {
-    Triple tent (0.f, 1.f, 1.f);
-    Triple axis_range (-1.f, -0.5f, 1.f);
-    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    Triple tent (0.0, 1.0, 1.0);
+    Triple axis_range (-1.0, -0.5, 1.0);
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
     assert (out.length == 1);
-    assert (out[0].first == 1.f);
-    assert (out[0].second == Triple (1.f/3, 1.f, 1.f));
+    assert (out[0].first == 1.0);
+    assert (out[0].second == Triple (1.0/3, 1.0, 1.0));
   }
 
   {
-    Triple tent (0.f, 1.f, 1.f);
-    Triple axis_range (-1.f, -0.5f, 1.f);
-    TripleDistances axis_distances{2.f, 1.f};
-    result_t out = rebase_tent (tent, axis_range, axis_distances);
+    Triple tent (0.0, 1.0, 1.0);
+    Triple axis_range (-1.0, -0.5, 1.0);
+    TripleDistances axis_distances{2.0, 1.0};
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, axis_distances);
     assert (out.length == 1);
-    assert (out[0].first == 1.f);
-    assert (out[0].second == Triple (0.5f, 1.f, 1.f));
+    assert (out[0].first == 1.0);
+    assert (out[0].second == Triple (0.5, 1.0, 1.0));
+  }
+
+  {
+    Triple tent (0.6, 0.7, 0.8);
+    Triple axis_range (-1.0, 0.2, 1.0);
+    TripleDistances axis_distances{1.0, 1.0};
+    rebase_tent_result_t out = rebase_tent (tent, axis_range, axis_distances);
+    assert (out.length == 1);
+    assert (out[0].first == 1.0);
+    assert (approx (out[0].second, Triple (0.5, 0.625, 0.75)));
   }
 }
-
diff --git a/src/test-tuple-varstore.cc b/src/test-tuple-varstore.cc
index 97fec25..16a4338 100644
--- a/src/test-tuple-varstore.cc
+++ b/src/test-tuple-varstore.cc
@@ -63,10 +63,10 @@
     assert (tuple_variations.tuple_vars[i].indices.length == 65);
     assert (tuple_variations.tuple_vars[i].indices.length == tuple_variations.tuple_vars[i].deltas_x.length);
   }
-  assert (tuple_variations.tuple_vars[0].axis_tuples.get (axis_tag) == Triple (-1.f, -1.f, 0.f));
-  assert (tuple_variations.tuple_vars[1].axis_tuples.get (axis_tag) == Triple (0.f, 1.f, 1.f));
-  
-  hb_vector_t<float> deltas_1 {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, -1.f, 0.f, -3.f, 1.f, 0.f, -1.f, 0.f, -3.f, 1.f, 0.f, -37.f, -37.f, -26.f, -26.f, 0.f, 0.f, 0.f, -3.f, 0.f, 0.f, 0.f, 0.f, 0.f, -3.f, 0.f, 2.f, -29.f, -29.f, -20.f, -20.f, 0.f, 0.f, 0.f, 1.f, -29.f, -29.f, -20.f, -20.f, 0.f, 0.f, 0.f, 1.f};
+  assert (tuple_variations.tuple_vars[0].axis_tuples.get (axis_tag) == Triple (-1.0, -1.0, 0.0));
+  assert (tuple_variations.tuple_vars[1].axis_tuples.get (axis_tag) == Triple (0.0, 1.0, 1.0));
+
+  hb_vector_t<double> deltas_1 {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, -3.0, 1.0, 0.0, -1.0, 0.0, -3.0, 1.0, 0.0, -37.0, -37.0, -26.0, -26.0, 0.0, 0.0, 0.0, -3.0, 0.0, 0.0, 0.0, 0.0, 0.0, -3.0, 0.0, 2.0, -29.0, -29.0, -20.0, -20.0, 0.0, 0.0, 0.0, 1.0, -29.0, -29.0, -20.0, -20.0, 0.0, 0.0, 0.0, 1.0};
   for (unsigned i = 0; i < 65; i++)
   {
     if (i < 23)
@@ -78,7 +78,7 @@
     }
   }
 
-  hb_vector_t<float> deltas_2 {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 5.f, -3.f, 0.f, 1.f, 0.f, 5.f, -3.f, 0.f, 97.f, 97.f, 68.f, 68.f, 0.f, 0.f, 0.f, 5.f, 0.f, 0.f, 1.f, -1.f, 1.f, 7.f, -1.f, -5.f, 73.f, 73.f, 53.f, 53.f, 0.f, 0.f, 0.f, -1.f, 73.f, 73.f, 53.f, 53.f, 0.f, 0.f, 0.f, -1.f};
+  hb_vector_t<double> deltas_2 {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 5.0, -3.0, 0.0, 1.0, 0.0, 5.0, -3.0, 0.0, 97.0, 97.0, 68.0, 68.0, 0.0, 0.0, 0.0, 5.0, 0.0, 0.0, 1.0, -1.0, 1.0, 7.0, -1.0, -5.0, 73.0, 73.0, 53.0, 53.0, 0.0, 0.0, 0.0, -1.0, 73.0, 73.0, 53.0, 53.0, 0.0, 0.0, 0.0, -1.0};
   for (unsigned i = 0 ; i < 65; i++)
   {
     if (i < 23)
@@ -92,10 +92,10 @@
 
   /* partial instancing wght=300:800 */
   hb_hashmap_t<hb_tag_t, Triple> normalized_axes_location;
-  normalized_axes_location.set (axis_tag, Triple (-0.512817f, 0.f, 0.700012f));
+  normalized_axes_location.set (axis_tag, Triple (-0.512817, 0.0, 0.700012));
 
   hb_hashmap_t<hb_tag_t, TripleDistances> axes_triple_distances;
-  axes_triple_distances.set (axis_tag, TripleDistances (1.f, 1.f));
+  axes_triple_distances.set (axis_tag, TripleDistances (1.0, 1.0));
 
   tuple_variations.instantiate (normalized_axes_location, axes_triple_distances);
 
@@ -103,12 +103,12 @@
   assert (tuple_variations.tuple_vars[1].indices.length == 65);
   assert (!tuple_variations.tuple_vars[0].deltas_y);
   assert (!tuple_variations.tuple_vars[1].deltas_y);
-  assert (tuple_variations.tuple_vars[0].axis_tuples.get (axis_tag) == Triple (-1.f, -1.f, 0.f));
-  assert (tuple_variations.tuple_vars[1].axis_tuples.get (axis_tag) == Triple (0.f, 1.f, 1.f));
+  assert (tuple_variations.tuple_vars[0].axis_tuples.get (axis_tag) == Triple (-1.0, -1.0, 0.0));
+  assert (tuple_variations.tuple_vars[1].axis_tuples.get (axis_tag) == Triple (0.0, 1.0, 1.0));
 
-  hb_vector_t<float> rounded_deltas_1 {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, -1, 0.f, -2, 1, 0.f, -1, 0.f, -2, 1, 0.f, -19, -19, -13, -13, 0.f, 0.f, 0.f, -2, 0.f, 0.f, 0.f, 0.f, 0.f, -2, 0.f, 1, -15, -15, -10.f, -10.f, 0.f, 0.f, 0.f, 1, -15, -15, -10.f, -10.f, 0.f, 0.f, 0.f, 1};
+  hb_vector_t<double> rounded_deltas_1 {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1, 0.0, -2, 1, 0.0, -1, 0.0, -2, 1, 0.0, -19, -19, -13, -13, 0.0, 0.0, 0.0, -2, 0.0, 0.0, 0.0, 0.0, 0.0, -2, 0.0, 1, -15, -15, -10.0, -10.0, 0.0, 0.0, 0.0, 1, -15, -15, -10.0, -10.0, 0.0, 0.0, 0.0, 1};
 
-  hb_vector_t<float> rounded_deltas_2 {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1, 0.f, 4, -2, 0.f, 1, 0.f, 4, -2, 0.f, 68, 68, 48, 48, 0.f, 0.f, 0.f, 4, 0.f, 0.f, 1, -1, 1, 5, -1, -4, 51, 51, 37, 37, 0.f, 0.f, 0.f, -1, 51, 51, 37, 37, 0.f, 0.f, 0.f, -1};
+  hb_vector_t<double> rounded_deltas_2 {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1, 0.0, 4, -2, 0.0, 1, 0.0, 4, -2, 0.0, 68, 68, 48, 48, 0.0, 0.0, 0.0, 4, 0.0, 0.0, 1, -1, 1, 5, -1, -4, 51, 51, 37, 37, 0.0, 0.0, 0.0, -1, 51, 51, 37, 37, 0.0, 0.0, 0.0, -1};
 
   for (unsigned i = 0; i < 65; i++)
   {
diff --git a/subprojects/packagefiles/ragel/meson.build b/subprojects/packagefiles/ragel/meson.build
index 4123ef2..c41ef0a 100644
--- a/subprojects/packagefiles/ragel/meson.build
+++ b/subprojects/packagefiles/ragel/meson.build
@@ -62,5 +62,5 @@
   meson.project_name(),
   ragel_sources,
   include_directories : ['aapl', 'ragel'],
-  install : true,
+  native : true,
 )
diff --git a/test/api/fonts/AdobeVFPrototype.abc.long_off.otf b/test/api/fonts/AdobeVFPrototype.abc.long_off.otf
new file mode 100644
index 0000000..a61926d
--- /dev/null
+++ b/test/api/fonts/AdobeVFPrototype.abc.long_off.otf
Binary files differ
diff --git a/test/api/fonts/AdobeVFPrototype.abc.otf b/test/api/fonts/AdobeVFPrototype.abc.otf
index 0e403a6..d938fae 100644
--- a/test/api/fonts/AdobeVFPrototype.abc.otf
+++ b/test/api/fonts/AdobeVFPrototype.abc.otf
Binary files differ
diff --git a/test/api/fonts/AdobeVFPrototype.abc.static.otf b/test/api/fonts/AdobeVFPrototype.abc.static.otf
index c5774cc..0c2e43d 100644
--- a/test/api/fonts/AdobeVFPrototype.abc.static.otf
+++ b/test/api/fonts/AdobeVFPrototype.abc.static.otf
Binary files differ
diff --git a/test/api/fonts/AdobeVFPrototype.ac.nohints.otf b/test/api/fonts/AdobeVFPrototype.ac.nohints.otf
index 55ab495..058dada 100644
--- a/test/api/fonts/AdobeVFPrototype.ac.nohints.otf
+++ b/test/api/fonts/AdobeVFPrototype.ac.nohints.otf
Binary files differ
diff --git a/test/api/fonts/AdobeVFPrototype.ac.nosubrs.otf b/test/api/fonts/AdobeVFPrototype.ac.nosubrs.otf
index d90f3ef..b6d8adf 100644
--- a/test/api/fonts/AdobeVFPrototype.ac.nosubrs.otf
+++ b/test/api/fonts/AdobeVFPrototype.ac.nosubrs.otf
Binary files differ
diff --git a/test/api/fonts/AdobeVFPrototype.ac.otf b/test/api/fonts/AdobeVFPrototype.ac.otf
index 96eb2eb..8e5272c 100644
--- a/test/api/fonts/AdobeVFPrototype.ac.otf
+++ b/test/api/fonts/AdobeVFPrototype.ac.otf
Binary files differ
diff --git a/test/api/fonts/AdobeVFPrototype.ac.retaingids.otf b/test/api/fonts/AdobeVFPrototype.ac.retaingids.otf
index 50b5be6..badc645 100644
--- a/test/api/fonts/AdobeVFPrototype.ac.retaingids.otf
+++ b/test/api/fonts/AdobeVFPrototype.ac.retaingids.otf
Binary files differ
diff --git a/test/api/fonts/NotoSans-Bold.ttf b/test/api/fonts/NotoSans-Bold.ttf
new file mode 100644
index 0000000..d84248e
--- /dev/null
+++ b/test/api/fonts/NotoSans-Bold.ttf
Binary files differ
diff --git a/test/api/fonts/Roboto-Variable.abc.long_loca.ttf b/test/api/fonts/Roboto-Variable.abc.long_loca.ttf
new file mode 100644
index 0000000..865ed9e
--- /dev/null
+++ b/test/api/fonts/Roboto-Variable.abc.long_loca.ttf
Binary files differ
diff --git a/test/api/fonts/Roboto-Variable.abc.ttf b/test/api/fonts/Roboto-Variable.abc.ttf
new file mode 100644
index 0000000..203f827
--- /dev/null
+++ b/test/api/fonts/Roboto-Variable.abc.ttf
Binary files differ
diff --git a/test/api/fonts/SourceHanSans-Regular.41,4C2E.nohints.otf b/test/api/fonts/SourceHanSans-Regular.41,4C2E.nohints.otf
index ec39590..d9b6cb5 100644
--- a/test/api/fonts/SourceHanSans-Regular.41,4C2E.nohints.otf
+++ b/test/api/fonts/SourceHanSans-Regular.41,4C2E.nohints.otf
Binary files differ
diff --git a/test/api/fonts/SourceHanSans-Regular.41,4C2E.nosubrs.nohints.otf b/test/api/fonts/SourceHanSans-Regular.41,4C2E.nosubrs.nohints.otf
index 00a112f..2d8f468 100644
--- a/test/api/fonts/SourceHanSans-Regular.41,4C2E.nosubrs.nohints.otf
+++ b/test/api/fonts/SourceHanSans-Regular.41,4C2E.nosubrs.nohints.otf
Binary files differ
diff --git a/test/api/fonts/SourceHanSans-Regular.41,4C2E.nosubrs.otf b/test/api/fonts/SourceHanSans-Regular.41,4C2E.nosubrs.otf
index 6fe9bf3..f4d5f6d 100644
--- a/test/api/fonts/SourceHanSans-Regular.41,4C2E.nosubrs.otf
+++ b/test/api/fonts/SourceHanSans-Regular.41,4C2E.nosubrs.otf
Binary files differ
diff --git a/test/api/fonts/SourceHanSans-Regular.41,4C2E.otf b/test/api/fonts/SourceHanSans-Regular.41,4C2E.otf
index 2c6cd9a..8dd9955 100644
--- a/test/api/fonts/SourceHanSans-Regular.41,4C2E.otf
+++ b/test/api/fonts/SourceHanSans-Regular.41,4C2E.otf
Binary files differ
diff --git a/test/api/fonts/SourceHanSans-Regular.41,4C2E.retaingids.otf b/test/api/fonts/SourceHanSans-Regular.41,4C2E.retaingids.otf
index 1e5cc96..0a11aa5 100644
--- a/test/api/fonts/SourceHanSans-Regular.41,4C2E.retaingids.otf
+++ b/test/api/fonts/SourceHanSans-Regular.41,4C2E.retaingids.otf
Binary files differ
diff --git a/test/api/fonts/SourceSansPro-Regular.abc.long_off.otf b/test/api/fonts/SourceSansPro-Regular.abc.long_off.otf
new file mode 100644
index 0000000..116921d
--- /dev/null
+++ b/test/api/fonts/SourceSansPro-Regular.abc.long_off.otf
Binary files differ
diff --git a/test/api/fonts/SourceSansPro-Regular.abc.otf b/test/api/fonts/SourceSansPro-Regular.abc.otf
index 7f51bd3..8b457ef 100644
--- a/test/api/fonts/SourceSansPro-Regular.abc.otf
+++ b/test/api/fonts/SourceSansPro-Regular.abc.otf
Binary files differ
diff --git a/test/api/fonts/SourceSansPro-Regular.ac.nohints.otf b/test/api/fonts/SourceSansPro-Regular.ac.nohints.otf
index 14a3a5f..b73cc35 100644
--- a/test/api/fonts/SourceSansPro-Regular.ac.nohints.otf
+++ b/test/api/fonts/SourceSansPro-Regular.ac.nohints.otf
Binary files differ
diff --git a/test/api/fonts/SourceSansPro-Regular.ac.nosubrs.nohints.otf b/test/api/fonts/SourceSansPro-Regular.ac.nosubrs.nohints.otf
index 69e244c..fe4b172 100644
--- a/test/api/fonts/SourceSansPro-Regular.ac.nosubrs.nohints.otf
+++ b/test/api/fonts/SourceSansPro-Regular.ac.nosubrs.nohints.otf
Binary files differ
diff --git a/test/api/fonts/SourceSansPro-Regular.ac.nosubrs.otf b/test/api/fonts/SourceSansPro-Regular.ac.nosubrs.otf
index 28edf13..13db824 100644
--- a/test/api/fonts/SourceSansPro-Regular.ac.nosubrs.otf
+++ b/test/api/fonts/SourceSansPro-Regular.ac.nosubrs.otf
Binary files differ
diff --git a/test/api/fonts/SourceSansPro-Regular.ac.otf b/test/api/fonts/SourceSansPro-Regular.ac.otf
index 12d6d0f..54d604d 100644
--- a/test/api/fonts/SourceSansPro-Regular.ac.otf
+++ b/test/api/fonts/SourceSansPro-Regular.ac.otf
Binary files differ
diff --git a/test/api/fonts/SourceSansPro-Regular.ac.retaingids.otf b/test/api/fonts/SourceSansPro-Regular.ac.retaingids.otf
index d364b48..7706c83 100644
--- a/test/api/fonts/SourceSansPro-Regular.ac.retaingids.otf
+++ b/test/api/fonts/SourceSansPro-Regular.ac.retaingids.otf
Binary files differ
diff --git a/test/api/fonts/cff1_dotsect.nohints.otf b/test/api/fonts/cff1_dotsect.nohints.otf
index faa932e..f9682e0 100644
--- a/test/api/fonts/cff1_dotsect.nohints.otf
+++ b/test/api/fonts/cff1_dotsect.nohints.otf
Binary files differ
diff --git a/test/api/fonts/cff1_expert.2D,F6E9,FB00.otf b/test/api/fonts/cff1_expert.2D,F6E9,FB00.otf
index dc79b69..0c33ab5 100644
--- a/test/api/fonts/cff1_expert.2D,F6E9,FB00.otf
+++ b/test/api/fonts/cff1_expert.2D,F6E9,FB00.otf
Binary files differ
diff --git a/test/api/fonts/cff1_seac.C0.otf b/test/api/fonts/cff1_seac.C0.otf
index aed2fdd..769b69d2 100644
--- a/test/api/fonts/cff1_seac.C0.otf
+++ b/test/api/fonts/cff1_seac.C0.otf
Binary files differ
diff --git a/test/api/hb-test.h b/test/api/hb-test.h
index 2be47be..e969ea8 100644
--- a/test/api/hb-test.h
+++ b/test/api/hb-test.h
@@ -172,6 +172,12 @@
 #ifndef g_assert_true
 #define g_assert_true g_assert
 #endif
+#ifndef g_assert_false
+#define g_assert_false(expr) g_assert(!(expr))
+#endif
+#ifndef g_assert_nonnull
+#define g_assert_nonnull  g_assert
+#endif
 #ifndef g_assert_cmpmem
 #define g_assert_cmpmem(m1, l1, m2, l2) g_assert_true (l1 == l2 && memcmp (m1, m2, l1) == 0)
 #endif
diff --git a/test/api/test-ot-math.c b/test/api/test-ot-math.c
index 6d87396..1510d2f 100644
--- a/test/api/test-ot-math.c
+++ b/test/api/test-ot-math.c
@@ -313,12 +313,12 @@
   g_assert(hb_font_get_glyph_from_name (hb_font, "I", -1, &glyph));
 
   g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 7), ==, 62); // lower than min height
-  g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 14), ==, 62); // equal to min height
+  g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 14), ==, 104); // equal to min height
   g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 20), ==, 104);
-  g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 23), ==, 104);
+  g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 23), ==, 146);
   g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 31), ==, 146);
-  g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 32), ==, 146);
-  g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 86), ==, 398); // equal to max height
+  g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 32), ==, 188);
+  g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 86), ==, 440); // equal to max height
   g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 91), ==, 440); // larger than max height
   g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 96), ==, 440); // larger than max height
 
@@ -746,7 +746,6 @@
   g_assert(!(parts[0].flags & HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER));
   g_assert(hb_font_get_glyph_from_name (hb_font, "vertical", -1, &glyph));
   g_assert_cmpint(parts[1].glyph, ==, glyph);
-  g_assert_cmpint(parts[1].glyph, ==, glyph);
   g_assert_cmpint(parts[1].start_connector_length, ==, 227);
   g_assert_cmpint(parts[1].end_connector_length, ==, 365);
   g_assert_cmpint(parts[1].full_advance, ==, 1000);
@@ -759,8 +758,6 @@
   g_assert(!(parts[2].flags & HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER));
   g_assert(hb_font_get_glyph_from_name (hb_font, "vertical", -1, &glyph));
   g_assert_cmpint(parts[3].glyph, ==, glyph);
-  g_assert_cmpint(parts[3].glyph, ==, glyph);
-  g_assert_cmpint(parts[3].glyph, ==, glyph);
   g_assert_cmpint(parts[3].start_connector_length, ==, 400);
   g_assert_cmpint(parts[3].end_connector_length, ==, 296);
   g_assert_cmpint(parts[3].full_advance, ==, 1000);
diff --git a/test/api/test-style.c b/test/api/test-style.c
index 27b135f..6478483 100644
--- a/test/api/test-style.c
+++ b/test/api/test-style.c
@@ -59,6 +59,23 @@
 }
 
 static void
+test_bold_face (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/NotoSans-Bold.ttf");
+  hb_font_t *font = hb_font_create (face);
+
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_ITALIC), 0);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_OPTICAL_SIZE), 12);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_SLANT_ANGLE), 0);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WIDTH), 100);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WEIGHT), 700);
+
+  hb_font_destroy (font);
+  hb_face_destroy (face);
+}
+
+
+static void
 test_face_user_setting (void)
 {
   hb_face_t *face = hb_test_open_font_file ("fonts/AdobeVFPrototype_vsindex.otf");
@@ -182,6 +199,7 @@
 
   hb_test_add (test_empty_face);
   hb_test_add (test_regular_face);
+  hb_test_add (test_bold_face);
   hb_test_add (test_face_user_setting);
   hb_test_add (test_synthetic_slant);
 
diff --git a/test/api/test-subset-cff1.c b/test/api/test-subset-cff1.c
index 7c68a49..f6a79a9 100644
--- a/test/api/test-subset-cff1.c
+++ b/test/api/test-subset-cff1.c
@@ -336,6 +336,34 @@
   hb_face_destroy (face_41_4c2e);
 }
 
+#ifdef HB_EXPERIMENTAL_API
+static void
+test_subset_cff1_iftb_requirements (void)
+{
+  hb_face_t *face_abc = hb_test_open_font_file ("fonts/SourceSansPro-Regular.abc.otf");
+  hb_face_t *face_long_off = hb_test_open_font_file ("fonts/SourceSansPro-Regular.abc.long_off.otf");
+
+  hb_set_t *codepoints = hb_set_create();
+  hb_face_t *face_abc_subset;
+  hb_set_add (codepoints, 97);
+  hb_set_add (codepoints, 98);
+  hb_set_add (codepoints, 99);
+
+  hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
+  hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_IFTB_REQUIREMENTS);
+  face_abc_subset = hb_subset_test_create_subset (face_abc, input);
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_long_off, face_abc_subset, HB_TAG ('C','F','F', ' '));
+
+  hb_face_destroy (face_abc_subset);
+  hb_face_destroy (face_abc);
+  hb_face_destroy (face_long_off);
+
+}
+#endif
+
+
 int
 main (int argc, char **argv)
 {
@@ -356,5 +384,9 @@
   hb_test_add (test_subset_cff1_retaingids);
   hb_test_add (test_subset_cff1_j_retaingids);
 
+#ifdef HB_EXPERIMENTAL_API
+  hb_test_add (test_subset_cff1_iftb_requirements);
+#endif
+
   return hb_test_run ();
 }
diff --git a/test/api/test-subset-cff2.c b/test/api/test-subset-cff2.c
index a5dde42..c7a5c06 100644
--- a/test/api/test-subset-cff2.c
+++ b/test/api/test-subset-cff2.c
@@ -161,6 +161,33 @@
   hb_face_destroy (face_ac);
 }
 
+#ifdef HB_EXPERIMENTAL_API
+static void
+test_subset_cff2_iftb_requirements (void)
+{
+  hb_face_t *face_abc = hb_test_open_font_file ("fonts/AdobeVFPrototype.abc.otf");
+  hb_face_t *face_long_off = hb_test_open_font_file ("fonts/AdobeVFPrototype.abc.long_off.otf");
+
+  hb_set_t *codepoints = hb_set_create();
+  hb_face_t *face_abc_subset;
+  hb_set_add (codepoints, 97);
+  hb_set_add (codepoints, 98);
+  hb_set_add (codepoints, 99);
+
+  hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
+  hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_IFTB_REQUIREMENTS);
+  face_abc_subset = hb_subset_test_create_subset (face_abc, input);
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_long_off, face_abc_subset, HB_TAG ('C','F','F', '2'));
+
+  hb_face_destroy (face_abc_subset);
+  hb_face_destroy (face_abc);
+  hb_face_destroy (face_long_off);
+
+}
+#endif
+
 int
 main (int argc, char **argv)
 {
@@ -173,5 +200,9 @@
   hb_test_add (test_subset_cff2_desubr_strip_hints);
   hb_test_add (test_subset_cff2_retaingids);
 
+#ifdef HB_EXPERIMENTAL_API
+  hb_test_add (test_subset_cff2_iftb_requirements);
+#endif
+
   return hb_test_run ();
 }
diff --git a/test/api/test-subset-glyf.c b/test/api/test-subset-glyf.c
index 94670be..aeead72 100644
--- a/test/api/test-subset-glyf.c
+++ b/test/api/test-subset-glyf.c
@@ -357,6 +357,35 @@
   hb_face_destroy (face_a);
 }
 
+#ifdef HB_EXPERIMENTAL_API
+static void
+test_subset_glyf_iftb_requirements (void)
+{
+  hb_face_t *face_abc = hb_test_open_font_file ("fonts/Roboto-Variable.abc.ttf");
+  hb_face_t *face_long_loca = hb_test_open_font_file ("fonts/Roboto-Variable.abc.long_loca.ttf");
+
+  hb_set_t *codepoints = hb_set_create();
+  hb_face_t *face_abc_subset;
+  hb_set_add (codepoints, 97);
+  hb_set_add (codepoints, 98);
+  hb_set_add (codepoints, 99);
+
+  hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
+  hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_IFTB_REQUIREMENTS);
+  face_abc_subset = hb_subset_test_create_subset (face_abc, input);
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_long_loca, face_abc_subset, HB_TAG ('l','o','c', 'a'));
+  hb_subset_test_check (face_long_loca, face_abc_subset, HB_TAG ('g','l','y','f'));
+  hb_subset_test_check (face_long_loca, face_abc_subset, HB_TAG ('g','v','a','r'));
+
+  hb_face_destroy (face_abc_subset);
+  hb_face_destroy (face_abc);
+  hb_face_destroy (face_long_loca);
+
+}
+#endif
+
 // TODO(grieger): test for long loca generation.
 
 int
@@ -377,5 +406,9 @@
   hb_test_add (test_subset_glyf_retain_gids);
   hb_test_add (test_subset_glyf_retain_gids_truncates);
 
+#ifdef HB_EXPERIMENTAL_API
+  hb_test_add (test_subset_glyf_iftb_requirements);
+#endif
+
   return hb_test_run();
 }
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6151390002806784 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6151390002806784
new file mode 100644
index 0000000..d80542c
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6151390002806784
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6159925345583104 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6159925345583104
new file mode 100644
index 0000000..715b9e8
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6159925345583104
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6696597055406080 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6696597055406080
new file mode 100644
index 0000000..65a2521
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6696597055406080
Binary files differ
diff --git a/test/fuzzing/fonts/crash-06c15853f99560aafddeda9f0879327b38475e07 b/test/fuzzing/fonts/crash-06c15853f99560aafddeda9f0879327b38475e07
new file mode 100644
index 0000000..68ba604
--- /dev/null
+++ b/test/fuzzing/fonts/crash-06c15853f99560aafddeda9f0879327b38475e07
Binary files differ
diff --git a/test/subset/data/Makefile.am b/test/subset/data/Makefile.am
index 9a7d08c..b220ba0 100644
--- a/test/subset/data/Makefile.am
+++ b/test/subset/data/Makefile.am
@@ -51,7 +51,7 @@
 	expected/colr \
 	expected/colr_glyphs \
 	expected/colrv1 \
-	expected/colrv1_copy_varstore \
+	expected/colrv1_subset_varstore \
 	expected/colr_with_components \
 	expected/cbdt \
 	expected/variable \
@@ -59,6 +59,7 @@
 	expected/glyph_map \
 	expected/math \
 	expected/math_coverage_offset \
+	expected/subset_base \
 	expected/post \
 	expected/full_instance \
 	expected/instance_feature_variations \
@@ -71,8 +72,19 @@
 	expected/post_apply_mvar_delta \
 	expected/apply_cvar_delta \
 	expected/collect_name_ids \
-	expected/instantiate_colrv1 \
 	expected/instantiate_cff2_update_metrics \
+	expected/layout.empty_ligature_offset \
+	expected/instantiate_base \
+	expected/instantiate_colrv1 \
+	expected/glyf_partial_instancing \
+	expected/feature_variations_partial_instance \
+	expected/update_def_wght \
+	expected/mvar_partial_instance \
+	expected/value_format_partial_instance \
+	expected/gdef_partial_instance \
+	expected/feature_variation_instance_collect_lookups \
+	expected/sync_vmetrics \
+	expected/empty_region_vardata \
 	fonts \
 	profiles \
 	$(NULL)
diff --git a/test/subset/data/Makefile.sources b/test/subset/data/Makefile.sources
index 398f2b8..0932ada 100644
--- a/test/subset/data/Makefile.sources
+++ b/test/subset/data/Makefile.sources
@@ -11,7 +11,7 @@
 	tests/colr.tests \
 	tests/colr_glyphs.tests \
 	tests/colrv1.tests \
-	tests/colrv1_copy_varstore.tests \
+	tests/colrv1_subset_varstore.tests \
 	tests/colr_with_components.tests \
 	tests/full-font.tests \
 	tests/glyf_bug_3131.tests \
@@ -50,6 +50,7 @@
 	tests/glyph_map.tests \
 	tests/math.tests \
 	tests/math_coverage_offset.tests \
+	tests/subset_base.tests \
 	tests/post.tests \
 	tests/full_instance.tests \
 	tests/instance_feature_variations.tests \
@@ -62,8 +63,19 @@
 	tests/post_apply_mvar_delta.tests \
 	tests/apply_cvar_delta.tests \
 	tests/collect_name_ids.tests \
-	tests/instantiate_colrv1.tests \
 	tests/instantiate_cff2_update_metrics.tests \
+	tests/layout.empty_ligature_offset.tests \
+	tests/instantiate_base.tests \
+	tests/instantiate_colrv1.tests \
+	tests/glyf_partial_instancing.tests \
+	tests/feature_variations_partial_instance.tests \
+	tests/update_def_wght.tests \
+	tests/mvar_partial_instance.tests \
+	tests/value_format_partial_instance.tests \
+	tests/gdef_partial_instance.tests \
+	tests/feature_variation_instance_collect_lookups.tests \
+	tests/sync_vmetrics.tests \
+	tests/empty_region_vardata.tests \
 	$(NULL)
 
 # TODO: re-enable once colrv1 subsetting is stabilized.
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,62,63,64.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,62,63,64.otf
index 6b28104..789657f 100644
--- a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,62,63,64.otf
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,62,63,64.otf
Binary files differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,62.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,62.otf
index 42a573e..e6e5c59 100644
--- a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,62.otf
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,62.otf
Binary files differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,63.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,63.otf
index 50f1965..14ee4db 100644
--- a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,63.otf
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,63.otf
Binary files differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,64.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,64.otf
index 77dbebe..fa7dc83 100644
--- a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,64.otf
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,64.otf
Binary files differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61.otf
index e2d1818..e30bf79 100644
--- a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61.otf
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61.otf
Binary files differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.62.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.62.otf
index bc42c26..6f39e81 100644
--- a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.62.otf
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.62.otf
Binary files differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.63.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.63.otf
index 7a3481d..8dc08c7 100644
--- a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.63.otf
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.63.otf
Binary files differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.64.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.64.otf
index 4fb8b80..deef223 100644
--- a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.64.otf
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.64.otf
Binary files differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,62,63,64.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,62,63,64.otf
index 6b28104..789657f 100644
--- a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,62,63,64.otf
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,62,63,64.otf
Binary files differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,62.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,62.otf
index 42a573e..e6e5c59 100644
--- a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,62.otf
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,62.otf
Binary files differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,63.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,63.otf
index 4b6ad6f..f0f276e 100644
--- a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,63.otf
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,63.otf
Binary files differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,64.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,64.otf
index c861f65..56b894f 100644
--- a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,64.otf
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,64.otf
Binary files differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61.otf
index e2d1818..e30bf79 100644
--- a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61.otf
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61.otf
Binary files differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.62.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.62.otf
index bfecc0c..deba25e 100644
--- a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.62.otf
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.62.otf
Binary files differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.63.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.63.otf
index d742e54..675ab33 100644
--- a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.63.otf
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.63.otf
Binary files differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.64.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.64.otf
index 69e32ea..911477f 100644
--- a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.64.otf
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.64.otf
Binary files differ
diff --git a/test/subset/data/expected/apply_cvar_delta/Comfortaa-Regular-new.default.retain-all-codepoint.wght=300.ttf b/test/subset/data/expected/apply_cvar_delta/Comfortaa-Regular-new.default.all.wght=300.ttf
similarity index 99%
rename from test/subset/data/expected/apply_cvar_delta/Comfortaa-Regular-new.default.retain-all-codepoint.wght=300.ttf
rename to test/subset/data/expected/apply_cvar_delta/Comfortaa-Regular-new.default.all.wght=300.ttf
index ca91b51..3b17439 100644
--- a/test/subset/data/expected/apply_cvar_delta/Comfortaa-Regular-new.default.retain-all-codepoint.wght=300.ttf
+++ b/test/subset/data/expected/apply_cvar_delta/Comfortaa-Regular-new.default.all.wght=300.ttf
Binary files differ
diff --git a/test/subset/data/expected/apply_cvar_delta/Comfortaa-Regular-new.default.retain-all-codepoint.wght=700.ttf b/test/subset/data/expected/apply_cvar_delta/Comfortaa-Regular-new.default.all.wght=700.ttf
similarity index 98%
rename from test/subset/data/expected/apply_cvar_delta/Comfortaa-Regular-new.default.retain-all-codepoint.wght=700.ttf
rename to test/subset/data/expected/apply_cvar_delta/Comfortaa-Regular-new.default.all.wght=700.ttf
index 2545786..69ea3a2 100644
--- a/test/subset/data/expected/apply_cvar_delta/Comfortaa-Regular-new.default.retain-all-codepoint.wght=700.ttf
+++ b/test/subset/data/expected/apply_cvar_delta/Comfortaa-Regular-new.default.all.wght=700.ttf
Binary files differ
diff --git a/test/subset/data/expected/apply_cvar_delta/Muli-ABC.default.retain-all-codepoint.wght=300.ttf b/test/subset/data/expected/apply_cvar_delta/Muli-ABC.default.all.wght=300.ttf
similarity index 85%
rename from test/subset/data/expected/apply_cvar_delta/Muli-ABC.default.retain-all-codepoint.wght=300.ttf
rename to test/subset/data/expected/apply_cvar_delta/Muli-ABC.default.all.wght=300.ttf
index d2680eb..add22af 100644
--- a/test/subset/data/expected/apply_cvar_delta/Muli-ABC.default.retain-all-codepoint.wght=300.ttf
+++ b/test/subset/data/expected/apply_cvar_delta/Muli-ABC.default.all.wght=300.ttf
Binary files differ
diff --git a/test/subset/data/expected/apply_cvar_delta/Muli-ABC.default.retain-all-codepoint.wght=700.ttf b/test/subset/data/expected/apply_cvar_delta/Muli-ABC.default.all.wght=700.ttf
similarity index 85%
rename from test/subset/data/expected/apply_cvar_delta/Muli-ABC.default.retain-all-codepoint.wght=700.ttf
rename to test/subset/data/expected/apply_cvar_delta/Muli-ABC.default.all.wght=700.ttf
index d590978..3c8b744 100644
--- a/test/subset/data/expected/apply_cvar_delta/Muli-ABC.default.retain-all-codepoint.wght=700.ttf
+++ b/test/subset/data/expected/apply_cvar_delta/Muli-ABC.default.all.wght=700.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61,62,63.ttf
index 61564e1..27feb4e 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61,63.ttf
index c5d1ca5..ade6ef3 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61.ttf
index 2fa7d5d..3fea482 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.62.ttf
index 210d224..69f8ad1 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.62.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.63.ttf
index 9f840d0..971c3cd 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.all.ttf
similarity index 99%
rename from test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf
rename to test/subset/data/expected/basics/Comfortaa-Regular-new.default.all.ttf
index 749ef45..7765884 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61,62,63.ttf
index 5b5033d..9642cd3 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61,63.ttf
index 29b2dc9..aa512d4 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61.ttf
index ac14d56..cb5408d 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.62.ttf
index eae3a89..6f9b69b 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.62.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.63.ttf
index 63690d0..aa7c976 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.all.ttf
similarity index 99%
rename from test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.retain-all-codepoint.ttf
rename to test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.all.ttf
index 8a7e828..b752b3c 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61,62,63.ttf
index f9a7acb..1e513e4 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61,63.ttf
index 3bba719..0d12792 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61.ttf
index 1759c85..ffc8c20 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.62.ttf
index 7accc1d..6ebd398 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.62.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.63.ttf
index 02fc4c5..e1b9379 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.all.ttf
similarity index 99%
rename from test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.retain-all-codepoint.ttf
rename to test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.all.ttf
index 711c070..d560386 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.61,62,63.ttf
index a12408b..ff91667 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.61,63.ttf
index ae965b8..109cb3d 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.61,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.61.ttf
index 2bc4119..68c9113 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.61.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.62.ttf
index 045a564..b863af7 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.62.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.63.ttf
index 127a085..c432b86 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.all.ttf
similarity index 99%
copy from test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf
copy to test/subset/data/expected/basics/Comfortaa-Regular-new.gids.all.ttf
index 749ef45..7765884 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.retain-all-codepoint.ttf
deleted file mode 100644
index 749ef45..0000000
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.61,62,63.ttf
index 50d5176..7a65b0e 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.61,63.ttf
index 8389377..bd04e5e 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.61,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.61.ttf
index 6de5862..60cfe24 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.61.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.62.ttf
index 86e9c79..7c764be 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.62.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.63.ttf
index c50cb5b..5c0dc68 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.all.ttf
similarity index 99%
rename from test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.retain-all-codepoint.ttf
rename to test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.all.ttf
index 56cba1b..3a16f49 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.61,62,63.ttf
index f86a38f..95a55f3 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.61,63.ttf
index 8a8dfab..8054539 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.61,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.61.ttf
index c2ac34c..729d798 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.61.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.62.ttf
index 210d224..69f8ad1 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.62.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.63.ttf
index 9f840d0..971c3cd 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.all.ttf
similarity index 98%
rename from test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.retain-all-codepoint.ttf
rename to test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.all.ttf
index e2fe5f9..94e6c21 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.61,62,63.ttf
index 61564e1..27feb4e 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.61,63.ttf
index c5d1ca5..ade6ef3 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.61,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.61.ttf
index 2fa7d5d..3fea482 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.61.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.62.ttf
index 210d224..69f8ad1 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.62.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.63.ttf
index 9f840d0..971c3cd 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.all.ttf
similarity index 98%
rename from test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.retain-all-codepoint.ttf
rename to test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.all.ttf
index 509ba2a..c52f12c 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61,62,63.ttf
index edc2749..222c334 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61,63.ttf
index 7f21708..a039c37 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61.ttf
index b5167c9..4b7c762 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.62.ttf
index 4240265..841bffb 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.62.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.63.ttf
index f7ae43d..810ebaa 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.all.ttf
similarity index 98%
rename from test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.retain-all-codepoint.ttf
rename to test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.all.ttf
index 660c052..3aad013 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.61,62,63.ttf
index 61564e1..27feb4e 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.61,63.ttf
index c5d1ca5..ade6ef3 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.61,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.61.ttf
index 2fa7d5d..3fea482 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.61.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.62.ttf
index 210d224..69f8ad1 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.62.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.63.ttf
index 9f840d0..971c3cd 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.all.ttf
similarity index 99%
copy from test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf
copy to test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.all.ttf
index 749ef45..7765884 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.retain-all-codepoint.ttf
deleted file mode 100644
index 749ef45..0000000
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.61,62,63.ttf
index 61564e1..27feb4e 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.61,63.ttf
index c5d1ca5..ade6ef3 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.61,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.61.ttf
index 2fa7d5d..3fea482 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.61.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.62.ttf
index 210d224..69f8ad1 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.62.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.63.ttf
index 9f840d0..971c3cd 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.all.ttf
similarity index 99%
copy from test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf
copy to test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.all.ttf
index 749ef45..7765884 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.retain-all-codepoint.ttf
deleted file mode 100644
index 749ef45..0000000
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.61,62,63.ttf
index 47315bd..4f18103 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.61,63.ttf
index 807f21d..2818273 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.61,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.61.ttf
index 8de6489..6080cd8 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.61.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.62.ttf
index 09396e2..abff0ec 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.62.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.63.ttf
index 1a62c02..0d51e8b 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.all.ttf
similarity index 99%
copy from test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf
copy to test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.all.ttf
index 749ef45..7765884 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.retain-all-codepoint.ttf
deleted file mode 100644
index 749ef45..0000000
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.61,62,63.ttf
index 876398a..a0be6ce 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.61,63.ttf
index c1ffb6f..a878589 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.61,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.61.ttf
index daba7e3..fb9a840 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.61.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.62.ttf
index 30087b5..da64ef5 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.62.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.63.ttf
index 1a084d5..9358884 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.all.ttf
similarity index 99%
rename from test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.retain-all-codepoint.ttf
rename to test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.all.ttf
index e33f66c..2f4b987 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61,62,63.ttf
index 727239c..d01bbf5 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61,63.ttf
index 02d67aa..9d6655e 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61.ttf
index 4eda654..4876feb 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.62.ttf
index cd321b7..23857bc 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.62.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.63.ttf
index 7b88b55..95d27bf 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.all.ttf
similarity index 99%
rename from test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.retain-all-codepoint.ttf
rename to test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.all.ttf
index 93aa982..b19ee0f 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.all.ttf
similarity index 100%
rename from test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.retain-all-codepoint.ttf
rename to test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.all.ttf
similarity index 100%
rename from test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.retain-all-codepoint.ttf
rename to test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.retain-all-codepoint.ttf
deleted file mode 100644
index b3d2945..0000000
--- a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.all.ttf
similarity index 100%
copy from test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.retain-all-codepoint.ttf
copy to test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.all.ttf
similarity index 100%
copy from test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.retain-all-codepoint.ttf
copy to test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.retain-all-codepoint.ttf
deleted file mode 100644
index f17e9fb..0000000
--- a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.glyph-names.all.ttf
similarity index 100%
copy from test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.retain-all-codepoint.ttf
copy to test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.glyph-names.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.glyph-names.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.glyph-names.retain-all-codepoint.ttf
deleted file mode 100644
index f17e9fb..0000000
--- a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.glyph-names.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.keep-all-layout-features.all.ttf
similarity index 100%
copy from test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.retain-all-codepoint.ttf
copy to test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.keep-all-layout-features.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.keep-all-layout-features.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.keep-all-layout-features.retain-all-codepoint.ttf
deleted file mode 100644
index f17e9fb..0000000
--- a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.keep-all-layout-features.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.layout-features.all.ttf
similarity index 100%
copy from test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.retain-all-codepoint.ttf
copy to test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.layout-features.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.layout-features.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.layout-features.retain-all-codepoint.ttf
deleted file mode 100644
index f17e9fb..0000000
--- a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.layout-features.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.all.ttf
similarity index 100%
rename from test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.retain-all-codepoint.ttf
rename to test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.all.ttf
similarity index 100%
rename from test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.retain-all-codepoint.ttf
rename to test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.all.ttf
similarity index 100%
copy from test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.retain-all-codepoint.ttf
copy to test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.retain-all-codepoint.ttf
deleted file mode 100644
index f17e9fb..0000000
--- a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.61,62,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.61,62,63.ttf
index 9854d47..5f0d98c 100644
--- a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.61,62,63.ttf
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.61,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.61,63.ttf
index c33b4cb..d2a94dd 100644
--- a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.61,63.ttf
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.61.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.61.ttf
index fefbfaf..e5f08c7 100644
--- a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.61.ttf
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.62.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.62.ttf
index a951a4c..6637064 100644
--- a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.62.ttf
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.63.ttf
index 349899d..8efd69b 100644
--- a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.63.ttf
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.all.ttf
similarity index 100%
copy from test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.retain-all-codepoint.ttf
copy to test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.retain-all-codepoint.ttf
deleted file mode 100644
index f17e9fb..0000000
--- a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.notdef-outline.all.ttf
similarity index 100%
copy from test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.retain-all-codepoint.ttf
copy to test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.notdef-outline.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.notdef-outline.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.notdef-outline.retain-all-codepoint.ttf
deleted file mode 100644
index f17e9fb..0000000
--- a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.notdef-outline.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.all.ttf
similarity index 100%
copy from test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.retain-all-codepoint.ttf
copy to test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.retain-all-codepoint.ttf
deleted file mode 100644
index f17e9fb..0000000
--- a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,62,63.ttf
index 8b2c634..69edba0 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,63.ttf
index 1f017da..84dee74 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.61.ttf
index d35619a..cf99a8c 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.default.61.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.default.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.62.ttf
index 5d73ef6..4833f51 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.default.62.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.default.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.63.ttf
index b384aed..4431714 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.default.63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.default.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.all.ttf
similarity index 76%
rename from test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf
rename to test/subset/data/expected/basics/Roboto-Regular.abc.default.all.ttf
index 8b2c634..69edba0 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.default.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,62,63.ttf
index 508510c..9d4fe9c 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,63.ttf
index b59987e..f463fcf 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61.ttf
index 36dd105..3ae4b15 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.62.ttf
index 8d9ffa4..1983877 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.62.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.63.ttf
index 3bc6e78..67437a0 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.all.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.all.ttf
new file mode 100644
index 0000000..9d4fe9c
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.retain-all-codepoint.ttf
deleted file mode 100644
index 508510c..0000000
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,62,63.ttf
index 508510c..9d4fe9c 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,63.ttf
index ac634f8..bcf7272 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61.ttf
index 36dd105..3ae4b15 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.62.ttf
index 8d0d8dd..c706025 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.62.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.63.ttf
index 54cd503..c9b5741 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.all.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.all.ttf
new file mode 100644
index 0000000..9d4fe9c
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.retain-all-codepoint.ttf
deleted file mode 100644
index 508510c..0000000
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.gids.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.61,62,63.ttf
index 8b2c634..69edba0 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.gids.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.gids.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.61,63.ttf
index 8b2c634..69edba0 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.gids.61,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.gids.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.61.ttf
index 8b2c634..69edba0 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.gids.61.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.gids.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.62.ttf
index 8b2c634..69edba0 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.gids.62.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.gids.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.63.ttf
index 8b2c634..69edba0 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.gids.63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.all.ttf
similarity index 76%
copy from test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf
copy to test/subset/data/expected/basics/Roboto-Regular.abc.gids.all.ttf
index 8b2c634..69edba0 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.retain-all-codepoint.ttf
deleted file mode 100644
index 8b2c634..0000000
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.gids.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.61,62,63.ttf
index 8b2c634..69edba0 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.61,63.ttf
index 1f017da..84dee74 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.61,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.61.ttf
index d35619a..cf99a8c 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.61.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.62.ttf
index 5d73ef6..4833f51 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.62.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.63.ttf
index b384aed..4431714 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.all.ttf
similarity index 76%
copy from test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf
copy to test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.all.ttf
index 8b2c634..69edba0 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.retain-all-codepoint.ttf
deleted file mode 100644
index 8b2c634..0000000
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.61,62,63.ttf
index 8b2c634..69edba0 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.61,63.ttf
index 1f017da..84dee74 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.61,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.61.ttf
index d35619a..cf99a8c 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.61.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.62.ttf
index 5d73ef6..4833f51 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.62.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.63.ttf
index b384aed..4431714 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.all.ttf
similarity index 76%
copy from test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf
copy to test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.all.ttf
index 8b2c634..69edba0 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.retain-all-codepoint.ttf
deleted file mode 100644
index 8b2c634..0000000
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.61,62,63.ttf
index 8b2c634..69edba0 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.61,63.ttf
index 1f017da..84dee74 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.61,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.61.ttf
index d35619a..cf99a8c 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.61.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.62.ttf
index 5d73ef6..4833f51 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.62.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.63.ttf
index b384aed..4431714 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.all.ttf
similarity index 76%
copy from test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf
copy to test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.all.ttf
index 8b2c634..69edba0 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.retain-all-codepoint.ttf
deleted file mode 100644
index 8b2c634..0000000
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,62,63.ttf
index 8b2c634..69edba0 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,63.ttf
index 1f017da..84dee74 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61.ttf
index d35619a..cf99a8c 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.62.ttf
index 5d73ef6..4833f51 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.62.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.63.ttf
index b384aed..4431714 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.all.ttf
similarity index 76%
copy from test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf
copy to test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.all.ttf
index 8b2c634..69edba0 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.retain-all-codepoint.ttf
deleted file mode 100644
index 8b2c634..0000000
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.61,62,63.ttf
index 8b2c634..69edba0 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.61,63.ttf
index 1f017da..84dee74 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.61,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.61.ttf
index d35619a..cf99a8c 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.61.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.62.ttf
index 5d73ef6..4833f51 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.62.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.63.ttf
index b384aed..4431714 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.all.ttf
similarity index 76%
copy from test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf
copy to test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.all.ttf
index 8b2c634..69edba0 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.retain-all-codepoint.ttf
deleted file mode 100644
index 8b2c634..0000000
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.61,62,63.ttf
index 8b2c634..69edba0 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.61,63.ttf
index 1f017da..84dee74 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.61,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.61.ttf
index d35619a..cf99a8c 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.61.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.62.ttf
index 5d73ef6..4833f51 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.62.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.63.ttf
index b384aed..4431714 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.all.ttf
similarity index 76%
copy from test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf
copy to test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.all.ttf
index 8b2c634..69edba0 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.retain-all-codepoint.ttf
deleted file mode 100644
index 8b2c634..0000000
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.61,62,63.ttf
index 8b2c634..69edba0 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.61,63.ttf
index 1f017da..84dee74 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.61,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.61.ttf
index 617e9fd..cf99a8c 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.61.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.62.ttf
index 91d71fd..4833f51 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.62.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.63.ttf
index c66b0b2..4431714 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.all.ttf
similarity index 76%
copy from test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf
copy to test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.all.ttf
index 8b2c634..69edba0 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.retain-all-codepoint.ttf
deleted file mode 100644
index 8b2c634..0000000
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.61,62,63.ttf
index 8b2c634..69edba0 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.61,63.ttf
index 1f017da..84dee74 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.61,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.61.ttf
index d35619a..cf99a8c 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.61.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.62.ttf
index 5d73ef6..4833f51 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.62.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.63.ttf
index b384aed..4431714 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.all.ttf
similarity index 76%
copy from test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf
copy to test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.all.ttf
index 8b2c634..69edba0 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.retain-all-codepoint.ttf
deleted file mode 100644
index 8b2c634..0000000
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,62,63.ttf
index 8b2c634..69edba0 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,63.ttf
index accefc9..b768004 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61.ttf
index d35619a..cf99a8c 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.62.ttf
index d4e5508..2687a48 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.62.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.63.ttf
index 350b166..15e5f80 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.all.ttf
similarity index 76%
copy from test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf
copy to test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.all.ttf
index 8b2c634..69edba0 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.retain-all-codepoint.ttf
deleted file mode 100644
index 8b2c634..0000000
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize-retain-gids.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize-retain-gids.1FC,21,41,20,62,63.otf
index a06d900..743a3c8 100644
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize-retain-gids.1FC,21,41,20,62,63.otf
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize-retain-gids.1FC,21,41,20,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize-retain-gids.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize-retain-gids.61,62,63.otf
index 1af511d..6d26f6c 100644
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize-retain-gids.61,62,63.otf
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize-retain-gids.61,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf
index 48ec219..ec83465 100644
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize.1FC,21,41,20,62,63.otf
index 179fc28..4f486ea 100644
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize.1FC,21,41,20,62,63.otf
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize.1FC,21,41,20,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize.61,62,63.otf
index 7a5e3ba..80c582b 100644
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize.61,62,63.otf
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize.61,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize.D7,D8,D9,DA,DE.otf
index 61999cb..07c74c2 100644
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize.D7,D8,D9,DA,DE.otf
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize.D7,D8,D9,DA,DE.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize-retain-gids.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize-retain-gids.1FC,21,41,20,62,63.otf
index 7b881e0..b80fee6 100644
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize-retain-gids.1FC,21,41,20,62,63.otf
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize-retain-gids.1FC,21,41,20,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize-retain-gids.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize-retain-gids.61,62,63.otf
index 59be7c3..a06f23f 100644
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize-retain-gids.61,62,63.otf
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize-retain-gids.61,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf
index 4b0aeeb..52b95c5 100644
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize.1FC,21,41,20,62,63.otf
index b60efdc..c4266c8 100644
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize.1FC,21,41,20,62,63.otf
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize.1FC,21,41,20,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize.61,62,63.otf
index a2a8d1a..0906138 100644
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize.61,62,63.otf
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize.61,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize.D7,D8,D9,DA,DE.otf
index 895b69d..6c464dd 100644
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize.D7,D8,D9,DA,DE.otf
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize.D7,D8,D9,DA,DE.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-retain-gids.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-retain-gids.1FC,21,41,20,62,63.otf
index 4024ffa..24249a8 100644
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-retain-gids.1FC,21,41,20,62,63.otf
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-retain-gids.1FC,21,41,20,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-retain-gids.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-retain-gids.61,62,63.otf
index 514ec3c..8866f0e 100644
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-retain-gids.61,62,63.otf
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-retain-gids.61,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-retain-gids.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-retain-gids.D7,D8,D9,DA,DE.otf
index f6d838c..592c20e 100644
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-retain-gids.D7,D8,D9,DA,DE.otf
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-retain-gids.D7,D8,D9,DA,DE.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints.1FC,21,41,20,62,63.otf
index 3c66f6d..778e149 100644
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints.1FC,21,41,20,62,63.otf
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints.1FC,21,41,20,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints.61,62,63.otf
index 4308642..52a45ce 100644
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints.61,62,63.otf
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints.61,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints.D7,D8,D9,DA,DE.otf
index 54dbd8f..910fd81 100644
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints.D7,D8,D9,DA,DE.otf
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints.D7,D8,D9,DA,DE.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-retain-gids.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-retain-gids.1FC,21,41,20,62,63.otf
index 268cefd..f97043d 100644
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-retain-gids.1FC,21,41,20,62,63.otf
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-retain-gids.1FC,21,41,20,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-retain-gids.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-retain-gids.61,62,63.otf
index 88c7b33..2631b95 100644
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-retain-gids.61,62,63.otf
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-retain-gids.61,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-retain-gids.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-retain-gids.D7,D8,D9,DA,DE.otf
index dd85287..5f7bf2f 100644
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-retain-gids.D7,D8,D9,DA,DE.otf
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-retain-gids.D7,D8,D9,DA,DE.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline.1FC,21,41,20,62,63.otf
index d5992f7..ab344d7 100644
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline.1FC,21,41,20,62,63.otf
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline.1FC,21,41,20,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline.61,62,63.otf
index de13277..3b5c82d 100644
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline.61,62,63.otf
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline.61,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline.D7,D8,D9,DA,DE.otf
index 90fdd95..a9fa710 100644
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline.D7,D8,D9,DA,DE.otf
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline.D7,D8,D9,DA,DE.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.3042,3044,3046,3048,304A,304B.otf
index 028434d..bce13b6 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.3042,3044,3046,3048,304A,304B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.3042,3044,3046,3048,304A,304B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.3042,3044,3046,73E0,5EA6,8F38.otf
index 73b2f01..887095d 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.3042,3044,3046,73E0,5EA6,8F38.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.3042,3044,3046,73E0,5EA6,8F38.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.61,63,65,6B.otf
index 3c99fb5..f2adb24 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.61,63,65,6B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.61,63,65,6B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.660E,6975,73E0,5EA6,8F38,6E05.otf
index f803b3e..33ec566 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.660E,6975,73E0,5EA6,8F38,6E05.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.660E,6975,73E0,5EA6,8F38,6E05.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.660E.otf
index d3b97c1..76f36ad 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.660E.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.660E.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.3042,3044,3046,3048,304A,304B.otf
index 2fd4d01..fa21161 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.3042,3044,3046,3048,304A,304B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.3042,3044,3046,3048,304A,304B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
index 8104df8..65c60cd 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.61,63,65,6B.otf
index 2eaaff3..d2a3ccc 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.61,63,65,6B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.61,63,65,6B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
index 02b738b..2e638b4 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.660E.otf
index 2e1aafe..deec7fc 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.660E.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.660E.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.3042,3044,3046,3048,304A,304B.otf
index e377284..75c851c 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.3042,3044,3046,3048,304A,304B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.3042,3044,3046,3048,304A,304B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf
index 0e613b7..27df94e 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.61,63,65,6B.otf
index d6a6ae7..0c47471 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.61,63,65,6B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.61,63,65,6B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf
index 839a963..814bb4d 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.660E.otf
index 71d39df..c61ff2d 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.660E.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.660E.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.3042,3044,3046,3048,304A,304B.otf
index 4c48a5a..b874a93 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.3042,3044,3046,3048,304A,304B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.3042,3044,3046,3048,304A,304B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
index 4e7e817..ef8339e 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.61,63,65,6B.otf
index 093927c..7f9e5b0 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.61,63,65,6B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.61,63,65,6B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
index 4471395..e16fdce 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.660E.otf
index 0ca639a..dff1b1e 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.660E.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.660E.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.3042,3044,3046,3048,304A,304B.otf
index ddd99b8..6506d21 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.3042,3044,3046,3048,304A,304B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.3042,3044,3046,3048,304A,304B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf
index af0b861..4765c4b 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.61,63,65,6B.otf
index 5aa7cc0..230c16a 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.61,63,65,6B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.61,63,65,6B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf
index 47e085e..6ed0997 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.660E.otf
index 7112ccc..4ac4e36 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.660E.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.660E.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.3042,3044,3046,3048,304A,304B.otf
index edd4687..14936d1 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.3042,3044,3046,3048,304A,304B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.3042,3044,3046,3048,304A,304B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
index 9c4a8f5..d486aef 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.61,63,65,6B.otf
index 81e2f2f..bcb8022 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.61,63,65,6B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.61,63,65,6B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
index 165e7f5..dce446c 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.660E.otf
index b3f7767..a029814 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.660E.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.660E.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.3042,3044,3046,3048,304A,304B.otf
index ad18ccc..cc985e0 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.3042,3044,3046,3048,304A,304B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.3042,3044,3046,3048,304A,304B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.3042,3044,3046,73E0,5EA6,8F38.otf
index e8df0b0..116b72b 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.3042,3044,3046,73E0,5EA6,8F38.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.3042,3044,3046,73E0,5EA6,8F38.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.61,63,65,6B.otf
index 7de6715..2d1681e 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.61,63,65,6B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.61,63,65,6B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.otf
index db8db37..9019edc 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.660E.otf
index d896e2f..5aa9f31 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.660E.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.660E.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.3042,3044,3046,3048,304A,304B.otf
index 24d8fae..081cadf 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.3042,3044,3046,3048,304A,304B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.3042,3044,3046,3048,304A,304B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
index 47af163..fc6278b 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.61,63,65,6B.otf
index 1503185..40bc541 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.61,63,65,6B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.61,63,65,6B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
index 4b08011..c57844a 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.660E.otf
index 40ef924..ef25699 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.660E.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.660E.otf
Binary files differ
diff --git a/test/subset/data/expected/cff.notoserifmyanmar/NotoSerifMyanmar-Regular.notdef-outline.1092.otf b/test/subset/data/expected/cff.notoserifmyanmar/NotoSerifMyanmar-Regular.notdef-outline.1092.otf
index 5935868..1c41da0 100644
--- a/test/subset/data/expected/cff.notoserifmyanmar/NotoSerifMyanmar-Regular.notdef-outline.1092.otf
+++ b/test/subset/data/expected/cff.notoserifmyanmar/NotoSerifMyanmar-Regular.notdef-outline.1092.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E00,4E02,4E03.otf
index 9a7689e..6f417f2 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E00,4E02,4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E00,4E02,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E00,4E03.otf
index 0e41c75..4f3902b 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E00,4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E00,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E00,4E05,4E07.otf
index 5830ba8..22d8b57 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E00,4E05,4E07.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E00,4E05,4E07.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E02,4E03,4E08.otf
index 2b59c26..e80e290 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E02,4E03,4E08.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E02,4E03,4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E02.otf
index 7883f60..21efe7a 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E02.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E02.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E03.otf
index 0c61722..6b68f70 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E05,4E07,4E08,4E09.otf
index 6be7ed3..2877b3c 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E05,4E07,4E08,4E09.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E05,4E07,4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E08,4E09.otf
index 7ff9072..69bcaaf 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E08,4E09.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E08.otf
index 4aac45a..a1c08be 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E08.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.all.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.all.otf
new file mode 100644
index 0000000..4558960
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.all.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.retain-all-codepoint.otf
deleted file mode 100644
index 0c8bdd4..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E00,4E02,4E03.otf
index bc44565..0412187 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E00,4E02,4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E00,4E02,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E00,4E03.otf
index 095724d..03ad26d 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E00,4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E00,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E00,4E05,4E07.otf
index 8deb80f..1b995fe 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E00,4E05,4E07.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E00,4E05,4E07.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E02,4E03,4E08.otf
index e03436c..543fec5 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E02,4E03,4E08.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E02,4E03,4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E02.otf
index 6042d7e..ff9f70c 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E02.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E02.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E03.otf
index e49657f..877c191 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E05,4E07,4E08,4E09.otf
index e4e2ad6..8a91fe0 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E05,4E07,4E08,4E09.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E05,4E07,4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E08,4E09.otf
index 0187125..c125b70 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E08,4E09.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E08.otf
index 97cbc62..0eb2f9e 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E08.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.all.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.all.otf
new file mode 100644
index 0000000..17e3de7
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.all.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.retain-all-codepoint.otf
deleted file mode 100644
index eda7a1f..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E00,4E02,4E03.otf
index 21cfd22..fbe79df 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E00,4E02,4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E00,4E02,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E00,4E03.otf
index 7bda9a9..2e0edaf 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E00,4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E00,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E00,4E05,4E07.otf
index 7557554..ec0fad3 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E00,4E05,4E07.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E00,4E05,4E07.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E02,4E03,4E08.otf
index 4dc196a..3767814 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E02,4E03,4E08.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E02,4E03,4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E02.otf
index bc54e22..87059e2 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E02.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E02.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E03.otf
index c1de48f..a99adda 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E05,4E07,4E08,4E09.otf
index d8d6f58..d4b3908 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E05,4E07,4E08,4E09.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E05,4E07,4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E08,4E09.otf
index 094a965..a1f9def 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E08,4E09.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E08.otf
index 7128ec4..ca9512a 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E08.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.all.otf
similarity index 84%
rename from test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.retain-all-codepoint.otf
rename to test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.all.otf
index 89866d8..a547d00 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.all.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E00,4E02,4E03.otf
index 8d49034..07f7b25 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E00,4E02,4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E00,4E02,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E00,4E03.otf
index 10e0362..c491db4 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E00,4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E00,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E00,4E05,4E07.otf
index 1e91545..3f35b19 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E00,4E05,4E07.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E00,4E05,4E07.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E02,4E03,4E08.otf
index 0c60f01..a26347d 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E02,4E03,4E08.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E02,4E03,4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E02.otf
index ce7842c..d0d6613e 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E02.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E02.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E03.otf
index da265e6..fbf8937 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E05,4E07,4E08,4E09.otf
index 52018d6..fc7f26b 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E05,4E07,4E08,4E09.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E05,4E07,4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E08,4E09.otf
index 0ba8353..8b41561 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E08,4E09.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E08.otf
index 4db7283..391218f 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E08.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.all.otf
similarity index 74%
rename from test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.retain-all-codepoint.otf
rename to test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.all.otf
index 803cbb6..7b0d59d 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.all.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E00,4E02,4E03.otf
index 62c8632..4a21201 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E00,4E02,4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E00,4E02,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E00,4E03.otf
index 1daaef8..bec789b 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E00,4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E00,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E00,4E05,4E07.otf
index 59f3b72..cacbb74 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E00,4E05,4E07.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E00,4E05,4E07.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E02,4E03,4E08.otf
index 1827c3f..09a8c3f 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E02,4E03,4E08.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E02,4E03,4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E02.otf
index 3e8d1d3..eaca75c 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E02.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E02.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E03.otf
index ba0dbd2..f0a95eb 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E05,4E07,4E08,4E09.otf
index dafe03c..2701ca1 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E05,4E07,4E08,4E09.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E05,4E07,4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E08,4E09.otf
index e779116..18a48b6 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E08,4E09.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E08.otf
index 7497dae..fcd8c4f 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E08.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.all.otf
similarity index 84%
rename from test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.retain-all-codepoint.otf
rename to test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.all.otf
index 22c1ca8..0d7ac35 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.all.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E00,4E02,4E03.otf
index 159a573..8bb85a6 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E00,4E02,4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E00,4E02,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E00,4E03.otf
index e21ca4f..137f165 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E00,4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E00,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E00,4E05,4E07.otf
index fbd6256..1b2dfdf 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E00,4E05,4E07.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E00,4E05,4E07.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E02,4E03,4E08.otf
index 1dc8d26..4dee169 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E02,4E03,4E08.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E02,4E03,4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E02.otf
index 82fc8b4..775a67c 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E02.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E02.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E03.otf
index b3f15b5..fcf8725 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E05,4E07,4E08,4E09.otf
index b9ef00e..0248360 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E05,4E07,4E08,4E09.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E05,4E07,4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E08,4E09.otf
index 77955aa..649feae 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E08,4E09.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E08.otf
index 5b4433e..8010c0f 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E08.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.all.otf
similarity index 75%
rename from test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.retain-all-codepoint.otf
rename to test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.all.otf
index b6a6e84..3a64c69 100644
--- a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.retain-all-codepoint.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.all.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E00,4E02,4E03.otf
index b63b9e2..a172018 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E00,4E02,4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E00,4E02,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E00,4E03.otf
index 15818ed..59ba9b2 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E00,4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E00,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E00,4E05,4E07.otf
index 74e2804..ed110b9 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E00,4E05,4E07.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E00,4E05,4E07.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E02,4E03,4E08.otf
index b7e6b17..996713e 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E02,4E03,4E08.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E02,4E03,4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E02.otf
index a342c31..dda3615 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E02.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E02.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E03.otf
index e4fcb04..8f0e542 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E05,4E07,4E08,4E09.otf
index 04312b7..9247f61 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E05,4E07,4E08,4E09.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E05,4E07,4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E08,4E09.otf
index 3b7cf7a..91bdcdd 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E08,4E09.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E08.otf
index fdd065b..6d4ea8f 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E08.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.all.otf
similarity index 88%
rename from test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.retain-all-codepoint.otf
rename to test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.all.otf
index 1cfbc63..2569912 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.all.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E00,4E02,4E03.otf
index 27805f7..a0a8321 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E00,4E02,4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E00,4E02,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E00,4E03.otf
index c54052f..8897d74 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E00,4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E00,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E00,4E05,4E07.otf
index ea4ea20..717f255 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E00,4E05,4E07.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E00,4E05,4E07.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E02,4E03,4E08.otf
index 6e74624..c90f248 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E02,4E03,4E08.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E02,4E03,4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E02.otf
index e7992bf..f364d0e 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E02.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E02.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E03.otf
index f31ed37..d2e4915 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E05,4E07,4E08,4E09.otf
index 6c3b011..eaa2943 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E05,4E07,4E08,4E09.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E05,4E07,4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E08,4E09.otf
index dc5c3f7..7bb0772 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E08,4E09.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E08.otf
index 516dd0e..c190700 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E08.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.all.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.all.otf
new file mode 100644
index 0000000..7bc8f6c
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.all.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.retain-all-codepoint.otf
deleted file mode 100644
index 31a1023..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E00,4E02,4E03.otf
index 3dcee76..d9d7645 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E00,4E02,4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E00,4E02,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E00,4E03.otf
index 8ce23a5..4619503 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E00,4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E00,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E00,4E05,4E07.otf
index e2b6cf9..eaab0aa 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E00,4E05,4E07.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E00,4E05,4E07.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E02,4E03,4E08.otf
index 7aea89a..1e00ded 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E02,4E03,4E08.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E02,4E03,4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E02.otf
index 6156ca9..986c80e 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E02.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E02.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E03.otf
index eb132d1..dd00dfb 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E05,4E07,4E08,4E09.otf
index 434d6d6..1eac8ee 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E05,4E07,4E08,4E09.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E05,4E07,4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E08,4E09.otf
index 0dfaad4..e4ec662 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E08,4E09.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E08.otf
index 6d72bbd..a1ac1e9 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E08.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.all.otf
similarity index 85%
rename from test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.retain-all-codepoint.otf
rename to test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.all.otf
index 76ecdba..c90857f 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.all.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E00,4E02,4E03.otf
index 387a7cc..21b6f7d 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E00,4E02,4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E00,4E02,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E00,4E03.otf
index c232dec..ed3e4eb 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E00,4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E00,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E00,4E05,4E07.otf
index 35b2f8d..9d591eb 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E00,4E05,4E07.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E00,4E05,4E07.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E02,4E03,4E08.otf
index b043082..19fdddb 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E02,4E03,4E08.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E02,4E03,4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E02.otf
index 3df697a..ab18162 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E02.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E02.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E03.otf
index 5719734..2065795 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E05,4E07,4E08,4E09.otf
index a15a74a..dc14f38 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E05,4E07,4E08,4E09.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E05,4E07,4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E08,4E09.otf
index 05bc0fb..bebffae 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E08,4E09.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E08.otf
index 26d7721..317e876 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E08.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.all.otf
similarity index 74%
rename from test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.retain-all-codepoint.otf
rename to test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.all.otf
index 7294e69..ac5d778 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.all.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E00,4E02,4E03.otf
index 908dfd6..7b3046a 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E00,4E02,4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E00,4E02,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E00,4E03.otf
index 4da6787..82efd78 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E00,4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E00,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E00,4E05,4E07.otf
index dad8165..fba35b0 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E00,4E05,4E07.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E00,4E05,4E07.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E02,4E03,4E08.otf
index 7788698..6669184 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E02,4E03,4E08.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E02,4E03,4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E02.otf
index 85c157f..b23afce 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E02.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E02.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E03.otf
index 8ffddaa..6e2a522 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E05,4E07,4E08,4E09.otf
index 1fb7a4c..b9a1ed1 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E05,4E07,4E08,4E09.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E05,4E07,4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E08,4E09.otf
index f446067..d48a5e1 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E08,4E09.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E08.otf
index 7c2ea2e..40c22d2 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E08.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.all.otf
similarity index 88%
rename from test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.retain-all-codepoint.otf
rename to test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.all.otf
index 10e5374..4931206 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.all.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E00,4E02,4E03.otf
index e4d4b36..1ad2629 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E00,4E02,4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E00,4E02,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E00,4E03.otf
index 31dbcd9..0925800 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E00,4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E00,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E00,4E05,4E07.otf
index 8a708ba..1ed837b 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E00,4E05,4E07.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E00,4E05,4E07.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E02,4E03,4E08.otf
index dee6213..778a2d6 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E02,4E03,4E08.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E02,4E03,4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E02.otf
index b8d991e..6989011 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E02.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E02.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E03.otf
index a939f5a..c6aeacd 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E03.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E05,4E07,4E08,4E09.otf
index ef379a0..cd02fda 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E05,4E07,4E08,4E09.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E05,4E07,4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E08,4E09.otf
index aac127a..13148c8 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E08,4E09.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E08.otf
index b4461a4..546ce34 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E08.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.all.otf
similarity index 77%
rename from test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.retain-all-codepoint.otf
rename to test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.all.otf
index 2c3cfd4..68f2c5b 100644
--- a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.retain-all-codepoint.otf
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.all.otf
Binary files differ
diff --git a/test/subset/data/expected/collect_name_ids/SourceSerif4Variable-Roman_subset.keep-all-layout-features.retain-all-codepoint.otf b/test/subset/data/expected/collect_name_ids/SourceSerif4Variable-Roman_subset.keep-all-layout-features.all.otf
similarity index 63%
rename from test/subset/data/expected/collect_name_ids/SourceSerif4Variable-Roman_subset.keep-all-layout-features.retain-all-codepoint.otf
rename to test/subset/data/expected/collect_name_ids/SourceSerif4Variable-Roman_subset.keep-all-layout-features.all.otf
index c375eaa..9280561 100644
--- a/test/subset/data/expected/collect_name_ids/SourceSerif4Variable-Roman_subset.keep-all-layout-features.retain-all-codepoint.otf
+++ b/test/subset/data/expected/collect_name_ids/SourceSerif4Variable-Roman_subset.keep-all-layout-features.all.otf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.default.E000,E004.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.default.E000,E004.ttf
index bab0b4f..6d11c9a 100644
--- a/test/subset/data/expected/colrv1/TestCOLRv1.default.E000,E004.ttf
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.default.E000,E004.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.default.E002,E003,E004.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.default.E002,E003,E004.ttf
index 7d094e0..25e2705 100644
--- a/test/subset/data/expected/colrv1/TestCOLRv1.default.E002,E003,E004.ttf
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.default.E002,E003,E004.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.default.E003,E004.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.default.E003,E004.ttf
index af8c79b..47f6bb0 100644
--- a/test/subset/data/expected/colrv1/TestCOLRv1.default.E003,E004.ttf
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.default.E003,E004.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.default.all.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.default.all.ttf
new file mode 100644
index 0000000..292799b
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.default.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.default.retain-all-codepoint.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.default.retain-all-codepoint.ttf
deleted file mode 100644
index b0e9865..0000000
--- a/test/subset/data/expected/colrv1/TestCOLRv1.default.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E000,E004.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E000,E004.ttf
index 3e9abac..36a6e75 100644
--- a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E000,E004.ttf
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E000,E004.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E002,E003,E004.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E002,E003,E004.ttf
index 25b5aed..97b032f 100644
--- a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E002,E003,E004.ttf
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E002,E003,E004.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E003,E004.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E003,E004.ttf
index f983408..e780c6e 100644
--- a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E003,E004.ttf
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E003,E004.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.all.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.all.ttf
new file mode 100644
index 0000000..c7545bb
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.retain-all-codepoint.ttf
deleted file mode 100644
index ec3ddec..0000000
--- a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E000,E004.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E000,E004.ttf
index 2c87b3d..3cdcea3 100644
--- a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E000,E004.ttf
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E000,E004.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E002,E003,E004.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E002,E003,E004.ttf
index dde87f7..c16fe7e 100644
--- a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E002,E003,E004.ttf
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E002,E003,E004.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E003,E004.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E003,E004.ttf
index 50be561..8122b36 100644
--- a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E003,E004.ttf
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E003,E004.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.all.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.all.ttf
new file mode 100644
index 0000000..c7545bb
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.retain-all-codepoint.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.retain-all-codepoint.ttf
deleted file mode 100644
index ec3ddec..0000000
--- a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E000,E004.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E000,E004.ttf
index 5d72345..cbe3f08 100644
--- a/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E000,E004.ttf
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E000,E004.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E002,E003,E004.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E002,E003,E004.ttf
index 549b52d..3ea9ae9 100644
--- a/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E002,E003,E004.ttf
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E002,E003,E004.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E003,E004.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E003,E004.ttf
index ec25389..d871c77 100644
--- a/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E003,E004.ttf
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E003,E004.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.all.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.all.ttf
new file mode 100644
index 0000000..292799b
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.retain-all-codepoint.ttf
deleted file mode 100644
index b0e9865..0000000
--- a/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/colrv1_copy_varstore/Foldit.default.41,42.ttf b/test/subset/data/expected/colrv1_copy_varstore/Foldit.default.41,42.ttf
deleted file mode 100644
index e28036b..0000000
--- a/test/subset/data/expected/colrv1_copy_varstore/Foldit.default.41,42.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/colrv1_copy_varstore/Foldit.default.41.ttf b/test/subset/data/expected/colrv1_copy_varstore/Foldit.default.41.ttf
deleted file mode 100644
index a75cd17..0000000
--- a/test/subset/data/expected/colrv1_copy_varstore/Foldit.default.41.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/colrv1_copy_varstore/Foldit.default.retain-all-codepoint.ttf b/test/subset/data/expected/colrv1_copy_varstore/Foldit.default.retain-all-codepoint.ttf
deleted file mode 100644
index 4981bd0..0000000
--- a/test/subset/data/expected/colrv1_copy_varstore/Foldit.default.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints-retain-gids.41,42.ttf b/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints-retain-gids.41,42.ttf
deleted file mode 100644
index d6d25f6..0000000
--- a/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints-retain-gids.41,42.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints-retain-gids.41.ttf b/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints-retain-gids.41.ttf
deleted file mode 100644
index 47d2eab..0000000
--- a/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints-retain-gids.41.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints-retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints-retain-gids.retain-all-codepoint.ttf
deleted file mode 100644
index 5df3ab1..0000000
--- a/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints-retain-gids.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints.41,42.ttf b/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints.41,42.ttf
deleted file mode 100644
index 48c337e..0000000
--- a/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints.41,42.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints.41.ttf b/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints.41.ttf
deleted file mode 100644
index 5777f2a..0000000
--- a/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints.41.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints.retain-all-codepoint.ttf b/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints.retain-all-codepoint.ttf
deleted file mode 100644
index 5df3ab1..0000000
--- a/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/colrv1_copy_varstore/Foldit.retain-gids.41,42.ttf b/test/subset/data/expected/colrv1_copy_varstore/Foldit.retain-gids.41,42.ttf
deleted file mode 100644
index 78cc03d..0000000
--- a/test/subset/data/expected/colrv1_copy_varstore/Foldit.retain-gids.41,42.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/colrv1_copy_varstore/Foldit.retain-gids.41.ttf b/test/subset/data/expected/colrv1_copy_varstore/Foldit.retain-gids.41.ttf
deleted file mode 100644
index 1abc3ec..0000000
--- a/test/subset/data/expected/colrv1_copy_varstore/Foldit.retain-gids.41.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/colrv1_copy_varstore/Foldit.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/colrv1_copy_varstore/Foldit.retain-gids.retain-all-codepoint.ttf
deleted file mode 100644
index 4981bd0..0000000
--- a/test/subset/data/expected/colrv1_copy_varstore/Foldit.retain-gids.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/colrv1_subset_varstore/Foldit.default.41,42.ttf b/test/subset/data/expected/colrv1_subset_varstore/Foldit.default.41,42.ttf
new file mode 100644
index 0000000..b3493a7
--- /dev/null
+++ b/test/subset/data/expected/colrv1_subset_varstore/Foldit.default.41,42.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1_subset_varstore/Foldit.default.41.ttf b/test/subset/data/expected/colrv1_subset_varstore/Foldit.default.41.ttf
new file mode 100644
index 0000000..ffc47f3
--- /dev/null
+++ b/test/subset/data/expected/colrv1_subset_varstore/Foldit.default.41.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1_subset_varstore/Foldit.default.all.ttf b/test/subset/data/expected/colrv1_subset_varstore/Foldit.default.all.ttf
new file mode 100644
index 0000000..80b97a4
--- /dev/null
+++ b/test/subset/data/expected/colrv1_subset_varstore/Foldit.default.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1_subset_varstore/Foldit.drop-hints-retain-gids.41,42.ttf b/test/subset/data/expected/colrv1_subset_varstore/Foldit.drop-hints-retain-gids.41,42.ttf
new file mode 100644
index 0000000..e96bd4d
--- /dev/null
+++ b/test/subset/data/expected/colrv1_subset_varstore/Foldit.drop-hints-retain-gids.41,42.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1_subset_varstore/Foldit.drop-hints-retain-gids.41.ttf b/test/subset/data/expected/colrv1_subset_varstore/Foldit.drop-hints-retain-gids.41.ttf
new file mode 100644
index 0000000..87250b3
--- /dev/null
+++ b/test/subset/data/expected/colrv1_subset_varstore/Foldit.drop-hints-retain-gids.41.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1_subset_varstore/Foldit.drop-hints-retain-gids.all.ttf b/test/subset/data/expected/colrv1_subset_varstore/Foldit.drop-hints-retain-gids.all.ttf
new file mode 100644
index 0000000..a29ff15
--- /dev/null
+++ b/test/subset/data/expected/colrv1_subset_varstore/Foldit.drop-hints-retain-gids.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1_subset_varstore/Foldit.drop-hints.41,42.ttf b/test/subset/data/expected/colrv1_subset_varstore/Foldit.drop-hints.41,42.ttf
new file mode 100644
index 0000000..c501dce
--- /dev/null
+++ b/test/subset/data/expected/colrv1_subset_varstore/Foldit.drop-hints.41,42.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1_subset_varstore/Foldit.drop-hints.41.ttf b/test/subset/data/expected/colrv1_subset_varstore/Foldit.drop-hints.41.ttf
new file mode 100644
index 0000000..b091a54
--- /dev/null
+++ b/test/subset/data/expected/colrv1_subset_varstore/Foldit.drop-hints.41.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1_subset_varstore/Foldit.drop-hints.all.ttf b/test/subset/data/expected/colrv1_subset_varstore/Foldit.drop-hints.all.ttf
new file mode 100644
index 0000000..a29ff15
--- /dev/null
+++ b/test/subset/data/expected/colrv1_subset_varstore/Foldit.drop-hints.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1_subset_varstore/Foldit.retain-gids.41,42.ttf b/test/subset/data/expected/colrv1_subset_varstore/Foldit.retain-gids.41,42.ttf
new file mode 100644
index 0000000..d398cd1
--- /dev/null
+++ b/test/subset/data/expected/colrv1_subset_varstore/Foldit.retain-gids.41,42.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1_subset_varstore/Foldit.retain-gids.41.ttf b/test/subset/data/expected/colrv1_subset_varstore/Foldit.retain-gids.41.ttf
new file mode 100644
index 0000000..5abaf09
--- /dev/null
+++ b/test/subset/data/expected/colrv1_subset_varstore/Foldit.retain-gids.41.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1_subset_varstore/Foldit.retain-gids.all.ttf b/test/subset/data/expected/colrv1_subset_varstore/Foldit.retain-gids.all.ttf
new file mode 100644
index 0000000..80b97a4
--- /dev/null
+++ b/test/subset/data/expected/colrv1_subset_varstore/Foldit.retain-gids.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/empty_region_vardata/RobotoFlex-Variable.ABC.default.all.wght=200-300,opsz=14.iup_optimize.ttf b/test/subset/data/expected/empty_region_vardata/RobotoFlex-Variable.ABC.default.all.wght=200-300,opsz=14.iup_optimize.ttf
new file mode 100644
index 0000000..b5eef2d
--- /dev/null
+++ b/test/subset/data/expected/empty_region_vardata/RobotoFlex-Variable.ABC.default.all.wght=200-300,opsz=14.iup_optimize.ttf
Binary files differ
diff --git a/test/subset/data/expected/empty_region_vardata/RobotoFlex-Variable.ABC.default.all.wght=200-300,opsz=14.ttf b/test/subset/data/expected/empty_region_vardata/RobotoFlex-Variable.ABC.default.all.wght=200-300,opsz=14.ttf
new file mode 100644
index 0000000..b7217b2
--- /dev/null
+++ b/test/subset/data/expected/empty_region_vardata/RobotoFlex-Variable.ABC.default.all.wght=200-300,opsz=14.ttf
Binary files differ
diff --git a/test/subset/data/expected/empty_region_vardata/RobotoFlex-Variable.ABC.default.all.wght=400,wdth=100,opsz=14.iup_optimize.ttf b/test/subset/data/expected/empty_region_vardata/RobotoFlex-Variable.ABC.default.all.wght=400,wdth=100,opsz=14.iup_optimize.ttf
new file mode 100644
index 0000000..557797e
--- /dev/null
+++ b/test/subset/data/expected/empty_region_vardata/RobotoFlex-Variable.ABC.default.all.wght=400,wdth=100,opsz=14.iup_optimize.ttf
Binary files differ
diff --git a/test/subset/data/expected/empty_region_vardata/RobotoFlex-Variable.ABC.default.all.wght=400,wdth=100,opsz=14.ttf b/test/subset/data/expected/empty_region_vardata/RobotoFlex-Variable.ABC.default.all.wght=400,wdth=100,opsz=14.ttf
new file mode 100644
index 0000000..ec32613
--- /dev/null
+++ b/test/subset/data/expected/empty_region_vardata/RobotoFlex-Variable.ABC.default.all.wght=400,wdth=100,opsz=14.ttf
Binary files differ
diff --git a/test/subset/data/expected/feature_variation_instance_collect_lookups/AnekBangla-question-subset.default.all.wdth=112.5.iup_optimize.ttf b/test/subset/data/expected/feature_variation_instance_collect_lookups/AnekBangla-question-subset.default.all.wdth=112.5.iup_optimize.ttf
new file mode 100644
index 0000000..8cf54c8
--- /dev/null
+++ b/test/subset/data/expected/feature_variation_instance_collect_lookups/AnekBangla-question-subset.default.all.wdth=112.5.iup_optimize.ttf
Binary files differ
diff --git a/test/subset/data/expected/feature_variation_instance_collect_lookups/AnekBangla-question-subset.default.all.wdth=112.5.ttf b/test/subset/data/expected/feature_variation_instance_collect_lookups/AnekBangla-question-subset.default.all.wdth=112.5.ttf
new file mode 100644
index 0000000..8cf54c8
--- /dev/null
+++ b/test/subset/data/expected/feature_variation_instance_collect_lookups/AnekBangla-question-subset.default.all.wdth=112.5.ttf
Binary files differ
diff --git a/test/subset/data/expected/feature_variations_partial_instance/NotoSansOriya-subset.default.all.wdth=75.iup_optimize.ttf b/test/subset/data/expected/feature_variations_partial_instance/NotoSansOriya-subset.default.all.wdth=75.iup_optimize.ttf
new file mode 100644
index 0000000..c88d0a5
--- /dev/null
+++ b/test/subset/data/expected/feature_variations_partial_instance/NotoSansOriya-subset.default.all.wdth=75.iup_optimize.ttf
Binary files differ
diff --git a/test/subset/data/expected/feature_variations_partial_instance/NotoSansOriya-subset.default.all.wdth=75.ttf b/test/subset/data/expected/feature_variations_partial_instance/NotoSansOriya-subset.default.all.wdth=75.ttf
new file mode 100644
index 0000000..00d9b34
--- /dev/null
+++ b/test/subset/data/expected/feature_variations_partial_instance/NotoSansOriya-subset.default.all.wdth=75.ttf
Binary files differ
diff --git a/test/subset/data/expected/feature_variations_partial_instance/NotoSansOriya-subset.keep-all-layout-features.all.wdth=75.iup_optimize.ttf b/test/subset/data/expected/feature_variations_partial_instance/NotoSansOriya-subset.keep-all-layout-features.all.wdth=75.iup_optimize.ttf
new file mode 100644
index 0000000..5f2d075
--- /dev/null
+++ b/test/subset/data/expected/feature_variations_partial_instance/NotoSansOriya-subset.keep-all-layout-features.all.wdth=75.iup_optimize.ttf
Binary files differ
diff --git a/test/subset/data/expected/feature_variations_partial_instance/NotoSansOriya-subset.keep-all-layout-features.all.wdth=75.ttf b/test/subset/data/expected/feature_variations_partial_instance/NotoSansOriya-subset.keep-all-layout-features.all.wdth=75.ttf
new file mode 100644
index 0000000..ea51cf3
--- /dev/null
+++ b/test/subset/data/expected/feature_variations_partial_instance/NotoSansOriya-subset.keep-all-layout-features.all.wdth=75.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.default.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.default.1FC,21,41,20,62,63.ttf
index 95852e3..2e8e176 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.default.1FC,21,41,20,62,63.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.default.1FC,21,41,20,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63,64,65,66,67,68,69,6A,6B.ttf
index b66269f..731b7a0 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63,64,65,66,67,68,69,6A,6B.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63,64,65,66,67,68,69,6A,6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63.ttf
index e2fe6e6..87ca843 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.default.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/Roboto-Regular.default.D7,D8,D9,DA,DE.ttf
index 372c13b..f8038df 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.default.D7,D8,D9,DA,DE.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.default.D7,D8,D9,DA,DE.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.1FC,21,41,20,62,63.ttf
index d1fd6d5..abc7bae 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.1FC,21,41,20,62,63.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.1FC,21,41,20,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63,64,65,66,67,68,69,6A,6B.ttf
index 4d50684..1fc716c 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63,64,65,66,67,68,69,6A,6B.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63,64,65,66,67,68,69,6A,6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63.ttf
index 429e4ce..dca118a 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.D7,D8,D9,DA,DE.ttf
index 6f7c0c1..0b04f59 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.D7,D8,D9,DA,DE.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.D7,D8,D9,DA,DE.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.1FC,21,41,20,62,63.ttf
index 38de0fe..8dc205f 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.1FC,21,41,20,62,63.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.1FC,21,41,20,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.1FC,21,41,20,62,63.ttf
index 2de0e2c..27ed69f 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.1FC,21,41,20,62,63.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.1FC,21,41,20,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.61,62,63,64,65,66,67,68,69,6A,6B.ttf
index cd3d30a..056bf50 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.61,62,63,64,65,66,67,68,69,6A,6B.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.61,62,63,64,65,66,67,68,69,6A,6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.61,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.61,62,63.ttf
index 3c04b26..2e9afb4 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.61,62,63.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.D7,D8,D9,DA,DE.ttf
index d7d7a73..6d6ff15 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.D7,D8,D9,DA,DE.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.D7,D8,D9,DA,DE.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.61,62,63,64,65,66,67,68,69,6A,6B.ttf
index 9dbd498..ed6a6ca 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.61,62,63,64,65,66,67,68,69,6A,6B.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.61,62,63,64,65,66,67,68,69,6A,6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.61,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.61,62,63.ttf
index 836df1c..0b0e274 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.61,62,63.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.D7,D8,D9,DA,DE.ttf
index 263c644..e66e568 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.D7,D8,D9,DA,DE.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.D7,D8,D9,DA,DE.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.1FC,21,41,20,62,63.ttf
index 6fed674..d7d982d 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.1FC,21,41,20,62,63.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.1FC,21,41,20,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf
index e6dd264..f79170c 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.61,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.61,62,63.ttf
index 5ecaaed..fff8cfd 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.61,62,63.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.D7,D8,D9,DA,DE.ttf
index 69d7875..5e6f362 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.D7,D8,D9,DA,DE.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.D7,D8,D9,DA,DE.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.1FC,21,41,20,62,63.ttf
index 5f46234..1d6f8da 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.1FC,21,41,20,62,63.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.1FC,21,41,20,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf
index 424209a..57baa27 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.61,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.61,62,63.ttf
index 5397c5b..247fce3 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.61,62,63.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.D7,D8,D9,DA,DE.ttf
index 8660d67..89c1437 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.D7,D8,D9,DA,DE.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.D7,D8,D9,DA,DE.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.1FC,21,41,20,62,63.ttf
index 43edc2c..9d6fc9d 100644
--- a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.1FC,21,41,20,62,63.ttf
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.1FC,21,41,20,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.61,62,63,64,65,66,67,68,69,6A,6B.ttf
index 57ff1f9..7a8dea8 100644
--- a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.61,62,63,64,65,66,67,68,69,6A,6B.ttf
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.61,62,63,64,65,66,67,68,69,6A,6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.61,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.61,62,63.ttf
index d049757..0741139 100644
--- a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.61,62,63.ttf
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.D7,D8,D9,DA,DE.ttf
index 205e9a8..06c2427 100644
--- a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.D7,D8,D9,DA,DE.ttf
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.D7,D8,D9,DA,DE.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.1FC,21,41,20,62,63.ttf
index b0069ab..2b35ad4 100644
--- a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.1FC,21,41,20,62,63.ttf
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.1FC,21,41,20,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.61,62,63,64,65,66,67,68,69,6A,6B.ttf
index 57ff1f9..7a8dea8 100644
--- a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.61,62,63,64,65,66,67,68,69,6A,6B.ttf
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.61,62,63,64,65,66,67,68,69,6A,6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.61,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.61,62,63.ttf
index d049757..0741139 100644
--- a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.61,62,63.ttf
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.D7,D8,D9,DA,DE.ttf
index 205e9a8..06c2427 100644
--- a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.D7,D8,D9,DA,DE.ttf
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.D7,D8,D9,DA,DE.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.1FC,21,41,20,62,63.ttf
index d450397..de7952a 100644
--- a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.1FC,21,41,20,62,63.ttf
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.1FC,21,41,20,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.1FC,21,41,20,62,63.ttf
index d7dbd75..7405e65 100644
--- a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.1FC,21,41,20,62,63.ttf
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.1FC,21,41,20,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.61,62,63,64,65,66,67,68,69,6A,6B.ttf
index f86d3dd..f23da05 100644
--- a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.61,62,63,64,65,66,67,68,69,6A,6B.ttf
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.61,62,63,64,65,66,67,68,69,6A,6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.61,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.61,62,63.ttf
index 03a14d0..4926a90 100644
--- a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.61,62,63.ttf
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.D7,D8,D9,DA,DE.ttf
index cac2b1e..2ec3c75 100644
--- a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.D7,D8,D9,DA,DE.ttf
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.D7,D8,D9,DA,DE.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.61,62,63,64,65,66,67,68,69,6A,6B.ttf
index 715c714..ecbdc5e 100644
--- a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.61,62,63,64,65,66,67,68,69,6A,6B.ttf
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.61,62,63,64,65,66,67,68,69,6A,6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.61,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.61,62,63.ttf
index 7d9ca25..f4010e1 100644
--- a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.61,62,63.ttf
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.D7,D8,D9,DA,DE.ttf
index b402ea9..6da5c11 100644
--- a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.D7,D8,D9,DA,DE.ttf
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.D7,D8,D9,DA,DE.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.1FC,21,41,20,62,63.ttf
index 40fb67a..6944a03 100644
--- a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.1FC,21,41,20,62,63.ttf
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.1FC,21,41,20,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf
index 28c3605..f8c221c 100644
--- a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.61,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.61,62,63.ttf
index 590ccb9..bc71acf 100644
--- a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.61,62,63.ttf
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.D7,D8,D9,DA,DE.ttf
index bbab9ca..56e55ec 100644
--- a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.D7,D8,D9,DA,DE.ttf
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.D7,D8,D9,DA,DE.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.1FC,21,41,20,62,63.ttf
index 08bdd83..2fc90e3 100644
--- a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.1FC,21,41,20,62,63.ttf
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.1FC,21,41,20,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf
index baa3468..42532e7 100644
--- a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.61,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.61,62,63.ttf
index 06dfe74..91086ad 100644
--- a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.61,62,63.ttf
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.D7,D8,D9,DA,DE.ttf
index c278d1f..7d117fb 100644
--- a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.D7,D8,D9,DA,DE.ttf
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.D7,D8,D9,DA,DE.ttf
Binary files differ
diff --git a/test/subset/data/expected/full_instance/Roboto-Variable.default.retain-all-codepoint.wght=150,wdth=80.ttf b/test/subset/data/expected/full_instance/Roboto-Variable.default.all.wght=150,wdth=80.ttf
similarity index 98%
rename from test/subset/data/expected/full_instance/Roboto-Variable.default.retain-all-codepoint.wght=150,wdth=80.ttf
rename to test/subset/data/expected/full_instance/Roboto-Variable.default.all.wght=150,wdth=80.ttf
index 6c7a145..d8b2b85 100644
--- a/test/subset/data/expected/full_instance/Roboto-Variable.default.retain-all-codepoint.wght=150,wdth=80.ttf
+++ b/test/subset/data/expected/full_instance/Roboto-Variable.default.all.wght=150,wdth=80.ttf
Binary files differ
diff --git a/test/subset/data/expected/full_instance/Roboto-Variable.default.retain-all-codepoint.wght=300,wdth=90.ttf b/test/subset/data/expected/full_instance/Roboto-Variable.default.all.wght=300,wdth=90.ttf
similarity index 98%
rename from test/subset/data/expected/full_instance/Roboto-Variable.default.retain-all-codepoint.wght=300,wdth=90.ttf
rename to test/subset/data/expected/full_instance/Roboto-Variable.default.all.wght=300,wdth=90.ttf
index 2a02cdb..9407bc4 100644
--- a/test/subset/data/expected/full_instance/Roboto-Variable.default.retain-all-codepoint.wght=300,wdth=90.ttf
+++ b/test/subset/data/expected/full_instance/Roboto-Variable.default.all.wght=300,wdth=90.ttf
Binary files differ
diff --git a/test/subset/data/expected/full_instance/Roboto-Variable.default.retain-all-codepoint.wght=150,wdth=80.ttf b/test/subset/data/expected/full_instance/Roboto-Variable.no-prune-unicode-ranges.all.wght=150,wdth=80.ttf
similarity index 98%
copy from test/subset/data/expected/full_instance/Roboto-Variable.default.retain-all-codepoint.wght=150,wdth=80.ttf
copy to test/subset/data/expected/full_instance/Roboto-Variable.no-prune-unicode-ranges.all.wght=150,wdth=80.ttf
index 6c7a145..d8b2b85 100644
--- a/test/subset/data/expected/full_instance/Roboto-Variable.default.retain-all-codepoint.wght=150,wdth=80.ttf
+++ b/test/subset/data/expected/full_instance/Roboto-Variable.no-prune-unicode-ranges.all.wght=150,wdth=80.ttf
Binary files differ
diff --git a/test/subset/data/expected/full_instance/Roboto-Variable.default.retain-all-codepoint.wght=300,wdth=90.ttf b/test/subset/data/expected/full_instance/Roboto-Variable.no-prune-unicode-ranges.all.wght=300,wdth=90.ttf
similarity index 98%
copy from test/subset/data/expected/full_instance/Roboto-Variable.default.retain-all-codepoint.wght=300,wdth=90.ttf
copy to test/subset/data/expected/full_instance/Roboto-Variable.no-prune-unicode-ranges.all.wght=300,wdth=90.ttf
index 2a02cdb..9407bc4 100644
--- a/test/subset/data/expected/full_instance/Roboto-Variable.default.retain-all-codepoint.wght=300,wdth=90.ttf
+++ b/test/subset/data/expected/full_instance/Roboto-Variable.no-prune-unicode-ranges.all.wght=300,wdth=90.ttf
Binary files differ
diff --git a/test/subset/data/expected/full_instance/Roboto-Variable.no-prune-unicode-ranges.retain-all-codepoint.wght=150,wdth=80.ttf b/test/subset/data/expected/full_instance/Roboto-Variable.no-prune-unicode-ranges.retain-all-codepoint.wght=150,wdth=80.ttf
deleted file mode 100644
index 6c7a145..0000000
--- a/test/subset/data/expected/full_instance/Roboto-Variable.no-prune-unicode-ranges.retain-all-codepoint.wght=150,wdth=80.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/full_instance/Roboto-Variable.no-prune-unicode-ranges.retain-all-codepoint.wght=300,wdth=90.ttf b/test/subset/data/expected/full_instance/Roboto-Variable.no-prune-unicode-ranges.retain-all-codepoint.wght=300,wdth=90.ttf
deleted file mode 100644
index 2a02cdb..0000000
--- a/test/subset/data/expected/full_instance/Roboto-Variable.no-prune-unicode-ranges.retain-all-codepoint.wght=300,wdth=90.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/gdef_partial_instance/AnekBangla-subset.default.all.wght=300.iup_optimize.ttf b/test/subset/data/expected/gdef_partial_instance/AnekBangla-subset.default.all.wght=300.iup_optimize.ttf
new file mode 100644
index 0000000..4d79c2c
--- /dev/null
+++ b/test/subset/data/expected/gdef_partial_instance/AnekBangla-subset.default.all.wght=300.iup_optimize.ttf
Binary files differ
diff --git a/test/subset/data/expected/gdef_partial_instance/AnekBangla-subset.default.all.wght=300.ttf b/test/subset/data/expected/gdef_partial_instance/AnekBangla-subset.default.all.wght=300.ttf
new file mode 100644
index 0000000..97c7b1a
--- /dev/null
+++ b/test/subset/data/expected/gdef_partial_instance/AnekBangla-subset.default.all.wght=300.ttf
Binary files differ
diff --git a/test/subset/data/expected/glyf_bug_3131/glyf_bug_3131.drop-hints-retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/glyf_bug_3131/glyf_bug_3131.drop-hints-retain-gids.all.ttf
similarity index 100%
rename from test/subset/data/expected/glyf_bug_3131/glyf_bug_3131.drop-hints-retain-gids.retain-all-codepoint.ttf
rename to test/subset/data/expected/glyf_bug_3131/glyf_bug_3131.drop-hints-retain-gids.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/glyf_bug_3131/glyf_bug_3131.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/glyf_bug_3131/glyf_bug_3131.retain-gids.all.ttf
similarity index 100%
rename from test/subset/data/expected/glyf_bug_3131/glyf_bug_3131.retain-gids.retain-all-codepoint.ttf
rename to test/subset/data/expected/glyf_bug_3131/glyf_bug_3131.retain-gids.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.ABC.no-tables-with-item-variations.retain-all-codepoint.wght=200-300-500,wdth=80-90.ttf b/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.ABC.default.all.wght=200-300-500,wdth=80-90.iup_optimize.ttf
similarity index 77%
copy from test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.ABC.no-tables-with-item-variations.retain-all-codepoint.wght=200-300-500,wdth=80-90.ttf
copy to test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.ABC.default.all.wght=200-300-500,wdth=80-90.iup_optimize.ttf
index 3dbbb91..edb3436 100644
--- a/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.ABC.no-tables-with-item-variations.retain-all-codepoint.wght=200-300-500,wdth=80-90.ttf
+++ b/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.ABC.default.all.wght=200-300-500,wdth=80-90.iup_optimize.ttf
Binary files differ
diff --git a/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.ABC.no-tables-with-item-variations.retain-all-codepoint.wght=200-300-500,wdth=80-90.ttf b/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.ABC.default.all.wght=200-300-500,wdth=80-90.ttf
similarity index 85%
rename from test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.ABC.no-tables-with-item-variations.retain-all-codepoint.wght=200-300-500,wdth=80-90.ttf
rename to test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.ABC.default.all.wght=200-300-500,wdth=80-90.ttf
index 3dbbb91..dc1e777 100644
--- a/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.ABC.no-tables-with-item-variations.retain-all-codepoint.wght=200-300-500,wdth=80-90.ttf
+++ b/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.ABC.default.all.wght=200-300-500,wdth=80-90.ttf
Binary files differ
diff --git a/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.ABC.no-tables-with-item-variations.retain-all-codepoint.wght=300-600,wdth=85.ttf b/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.ABC.default.all.wght=300-600,wdth=85.iup_optimize.ttf
similarity index 88%
rename from test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.ABC.no-tables-with-item-variations.retain-all-codepoint.wght=300-600,wdth=85.ttf
rename to test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.ABC.default.all.wght=300-600,wdth=85.iup_optimize.ttf
index 00dc29d..4f5c057 100644
--- a/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.ABC.no-tables-with-item-variations.retain-all-codepoint.wght=300-600,wdth=85.ttf
+++ b/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.ABC.default.all.wght=300-600,wdth=85.iup_optimize.ttf
Binary files differ
diff --git a/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.ABC.no-tables-with-item-variations.retain-all-codepoint.wght=300-600,wdth=85.ttf b/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.ABC.default.all.wght=300-600,wdth=85.ttf
similarity index 88%
copy from test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.ABC.no-tables-with-item-variations.retain-all-codepoint.wght=300-600,wdth=85.ttf
copy to test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.ABC.default.all.wght=300-600,wdth=85.ttf
index 00dc29d..4f5c057 100644
--- a/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.ABC.no-tables-with-item-variations.retain-all-codepoint.wght=300-600,wdth=85.ttf
+++ b/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.ABC.default.all.wght=300-600,wdth=85.ttf
Binary files differ
diff --git a/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.no-tables-with-item-variations.retain-all-codepoint.wght=200-300-500,wdth=80-90.ttf b/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.default.all.wght=200-300-500,wdth=80-90.iup_optimize.ttf
similarity index 76%
copy from test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.no-tables-with-item-variations.retain-all-codepoint.wght=200-300-500,wdth=80-90.ttf
copy to test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.default.all.wght=200-300-500,wdth=80-90.iup_optimize.ttf
index e8a85f4..fd7f157 100644
--- a/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.no-tables-with-item-variations.retain-all-codepoint.wght=200-300-500,wdth=80-90.ttf
+++ b/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.default.all.wght=200-300-500,wdth=80-90.iup_optimize.ttf
Binary files differ
diff --git a/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.no-tables-with-item-variations.retain-all-codepoint.wght=200-300-500,wdth=80-90.ttf b/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.default.all.wght=200-300-500,wdth=80-90.ttf
similarity index 88%
rename from test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.no-tables-with-item-variations.retain-all-codepoint.wght=200-300-500,wdth=80-90.ttf
rename to test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.default.all.wght=200-300-500,wdth=80-90.ttf
index e8a85f4..4983f0d 100644
--- a/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.no-tables-with-item-variations.retain-all-codepoint.wght=200-300-500,wdth=80-90.ttf
+++ b/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.default.all.wght=200-300-500,wdth=80-90.ttf
Binary files differ
diff --git a/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.no-tables-with-item-variations.retain-all-codepoint.wght=300-600,wdth=85.ttf b/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.default.all.wght=300-600,wdth=85.iup_optimize.ttf
similarity index 86%
copy from test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.no-tables-with-item-variations.retain-all-codepoint.wght=300-600,wdth=85.ttf
copy to test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.default.all.wght=300-600,wdth=85.iup_optimize.ttf
index 4fc5621..10ca9fb 100644
--- a/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.no-tables-with-item-variations.retain-all-codepoint.wght=300-600,wdth=85.ttf
+++ b/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.default.all.wght=300-600,wdth=85.iup_optimize.ttf
Binary files differ
diff --git a/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.no-tables-with-item-variations.retain-all-codepoint.wght=300-600,wdth=85.ttf b/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.default.all.wght=300-600,wdth=85.ttf
similarity index 90%
rename from test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.no-tables-with-item-variations.retain-all-codepoint.wght=300-600,wdth=85.ttf
rename to test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.default.all.wght=300-600,wdth=85.ttf
index 4fc5621..e96c240 100644
--- a/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.no-tables-with-item-variations.retain-all-codepoint.wght=300-600,wdth=85.ttf
+++ b/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.default.all.wght=300-600,wdth=85.ttf
Binary files differ
diff --git a/test/subset/data/expected/glyph_map/Roboto-Regular.glyph_map_roboto.41,43,61,66,69.ttf b/test/subset/data/expected/glyph_map/Roboto-Regular.glyph_map_roboto.41,43,61,66,69.ttf
index a4c8266..63f5e82 100644
--- a/test/subset/data/expected/glyph_map/Roboto-Regular.glyph_map_roboto.41,43,61,66,69.ttf
+++ b/test/subset/data/expected/glyph_map/Roboto-Regular.glyph_map_roboto.41,43,61,66,69.ttf
Binary files differ
diff --git a/test/subset/data/expected/glyph_names/Ubuntu-Regular.glyph-names.retain-all-codepoint.ttf b/test/subset/data/expected/glyph_names/Ubuntu-Regular.glyph-names.all.ttf
similarity index 100%
rename from test/subset/data/expected/glyph_names/Ubuntu-Regular.glyph-names.retain-all-codepoint.ttf
rename to test/subset/data/expected/glyph_names/Ubuntu-Regular.glyph-names.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/iftb_requirements/AdobeVFPrototype.default.61,62,63.otf b/test/subset/data/expected/iftb_requirements/AdobeVFPrototype.default.61,62,63.otf
new file mode 100644
index 0000000..d938fae
--- /dev/null
+++ b/test/subset/data/expected/iftb_requirements/AdobeVFPrototype.default.61,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/iftb_requirements/AdobeVFPrototype.iftb_requirements.61,62,63.otf b/test/subset/data/expected/iftb_requirements/AdobeVFPrototype.iftb_requirements.61,62,63.otf
new file mode 100644
index 0000000..a61926d
--- /dev/null
+++ b/test/subset/data/expected/iftb_requirements/AdobeVFPrototype.iftb_requirements.61,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/iftb_requirements/Roboto-Variable.default.61,62,63.ttf b/test/subset/data/expected/iftb_requirements/Roboto-Variable.default.61,62,63.ttf
new file mode 100644
index 0000000..203f827
--- /dev/null
+++ b/test/subset/data/expected/iftb_requirements/Roboto-Variable.default.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/iftb_requirements/Roboto-Variable.iftb_requirements.61,62,63.ttf b/test/subset/data/expected/iftb_requirements/Roboto-Variable.iftb_requirements.61,62,63.ttf
new file mode 100644
index 0000000..865ed9e
--- /dev/null
+++ b/test/subset/data/expected/iftb_requirements/Roboto-Variable.iftb_requirements.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/iftb_requirements/SourceSansPro-Regular.default.61,62,63.otf b/test/subset/data/expected/iftb_requirements/SourceSansPro-Regular.default.61,62,63.otf
new file mode 100644
index 0000000..3b5c82d
--- /dev/null
+++ b/test/subset/data/expected/iftb_requirements/SourceSansPro-Regular.default.61,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/iftb_requirements/SourceSansPro-Regular.iftb_requirements.61,62,63.otf b/test/subset/data/expected/iftb_requirements/SourceSansPro-Regular.iftb_requirements.61,62,63.otf
new file mode 100644
index 0000000..50c8f51
--- /dev/null
+++ b/test/subset/data/expected/iftb_requirements/SourceSansPro-Regular.iftb_requirements.61,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/instance_comp_glyph_empty_child/RobotoMono.default.retain-all-codepoint.wght=700.ttf b/test/subset/data/expected/instance_comp_glyph_empty_child/RobotoMono.default.all.wght=700.ttf
similarity index 100%
rename from test/subset/data/expected/instance_comp_glyph_empty_child/RobotoMono.default.retain-all-codepoint.wght=700.ttf
rename to test/subset/data/expected/instance_comp_glyph_empty_child/RobotoMono.default.all.wght=700.ttf
Binary files differ
diff --git a/test/subset/data/expected/instance_feature_variations/MPLUS1-Variable.default.30DD.wght=100.ttf b/test/subset/data/expected/instance_feature_variations/MPLUS1-Variable.default.30DD.wght=100.ttf
index 7026094..b5a0e23 100644
--- a/test/subset/data/expected/instance_feature_variations/MPLUS1-Variable.default.30DD.wght=100.ttf
+++ b/test/subset/data/expected/instance_feature_variations/MPLUS1-Variable.default.30DD.wght=100.ttf
Binary files differ
diff --git a/test/subset/data/expected/instance_feature_variations/MPLUS1-Variable.default.30DD.wght=400.ttf b/test/subset/data/expected/instance_feature_variations/MPLUS1-Variable.default.30DD.wght=400.ttf
index a01f7bc..3a49bf3 100644
--- a/test/subset/data/expected/instance_feature_variations/MPLUS1-Variable.default.30DD.wght=400.ttf
+++ b/test/subset/data/expected/instance_feature_variations/MPLUS1-Variable.default.30DD.wght=400.ttf
Binary files differ
diff --git a/test/subset/data/expected/instance_no_double_free/Handjet.default.all.wght=100,ELGR=1,ELSH=2.ttf b/test/subset/data/expected/instance_no_double_free/Handjet.default.all.wght=100,ELGR=1,ELSH=2.ttf
new file mode 100644
index 0000000..f71381b
--- /dev/null
+++ b/test/subset/data/expected/instance_no_double_free/Handjet.default.all.wght=100,ELGR=1,ELSH=2.ttf
Binary files differ
diff --git a/test/subset/data/expected/instance_no_double_free/Handjet.default.retain-all-codepoint.wght=100,ELGR=1,ELSH=2.ttf b/test/subset/data/expected/instance_no_double_free/Handjet.default.retain-all-codepoint.wght=100,ELGR=1,ELSH=2.ttf
deleted file mode 100644
index 87aa06b..0000000
--- a/test/subset/data/expected/instance_no_double_free/Handjet.default.retain-all-codepoint.wght=100,ELGR=1,ELSH=2.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/instance_no_double_free/Handjet.notdef-outline.all.wght=100,ELGR=1,ELSH=2.ttf b/test/subset/data/expected/instance_no_double_free/Handjet.notdef-outline.all.wght=100,ELGR=1,ELSH=2.ttf
new file mode 100644
index 0000000..803066f
--- /dev/null
+++ b/test/subset/data/expected/instance_no_double_free/Handjet.notdef-outline.all.wght=100,ELGR=1,ELSH=2.ttf
Binary files differ
diff --git a/test/subset/data/expected/instance_no_double_free/Handjet.notdef-outline.retain-all-codepoint.wght=100,ELGR=1,ELSH=2.ttf b/test/subset/data/expected/instance_no_double_free/Handjet.notdef-outline.retain-all-codepoint.wght=100,ELGR=1,ELSH=2.ttf
deleted file mode 100644
index ca588d1..0000000
--- a/test/subset/data/expected/instance_no_double_free/Handjet.notdef-outline.retain-all-codepoint.wght=100,ELGR=1,ELSH=2.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/instantiate_base/NotoSerifHK-subset.default.all.wght=400-600.ttf b/test/subset/data/expected/instantiate_base/NotoSerifHK-subset.default.all.wght=400-600.ttf
new file mode 100644
index 0000000..9cf667f
--- /dev/null
+++ b/test/subset/data/expected/instantiate_base/NotoSerifHK-subset.default.all.wght=400-600.ttf
Binary files differ
diff --git a/test/subset/data/expected/instantiate_base/NotoSerifHK-subset.default.all.wght=500.ttf b/test/subset/data/expected/instantiate_base/NotoSerifHK-subset.default.all.wght=500.ttf
new file mode 100644
index 0000000..f1be3f9
--- /dev/null
+++ b/test/subset/data/expected/instantiate_base/NotoSerifHK-subset.default.all.wght=500.ttf
Binary files differ
diff --git a/test/subset/data/expected/instantiate_cff2/AdobeVFPrototype.default.retain-all-codepoint.wght=650,CNTR=50.otf b/test/subset/data/expected/instantiate_cff2/AdobeVFPrototype.default.all.wght=650,CNTR=50.otf
similarity index 98%
rename from test/subset/data/expected/instantiate_cff2/AdobeVFPrototype.default.retain-all-codepoint.wght=650,CNTR=50.otf
rename to test/subset/data/expected/instantiate_cff2/AdobeVFPrototype.default.all.wght=650,CNTR=50.otf
index a870015..acf48c3 100644
--- a/test/subset/data/expected/instantiate_cff2/AdobeVFPrototype.default.retain-all-codepoint.wght=650,CNTR=50.otf
+++ b/test/subset/data/expected/instantiate_cff2/AdobeVFPrototype.default.all.wght=650,CNTR=50.otf
Binary files differ
diff --git a/test/subset/data/expected/instantiate_cff2_update_metrics/Cantarell-VF-ABC.default.all.wght=800.otf b/test/subset/data/expected/instantiate_cff2_update_metrics/Cantarell-VF-ABC.default.all.wght=800.otf
new file mode 100644
index 0000000..0ce0785
--- /dev/null
+++ b/test/subset/data/expected/instantiate_cff2_update_metrics/Cantarell-VF-ABC.default.all.wght=800.otf
Binary files differ
diff --git a/test/subset/data/expected/instantiate_cff2_update_metrics/Cantarell-VF-ABC.default.retain-all-codepoint.wght=800.otf b/test/subset/data/expected/instantiate_cff2_update_metrics/Cantarell-VF-ABC.default.retain-all-codepoint.wght=800.otf
deleted file mode 100644
index def60cf..0000000
--- a/test/subset/data/expected/instantiate_cff2_update_metrics/Cantarell-VF-ABC.default.retain-all-codepoint.wght=800.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/instantiate_cff2_update_metrics/Cantarell-VF-ABC.retain-gids.all.wght=800.otf b/test/subset/data/expected/instantiate_cff2_update_metrics/Cantarell-VF-ABC.retain-gids.all.wght=800.otf
new file mode 100644
index 0000000..0ce0785
--- /dev/null
+++ b/test/subset/data/expected/instantiate_cff2_update_metrics/Cantarell-VF-ABC.retain-gids.all.wght=800.otf
Binary files differ
diff --git a/test/subset/data/expected/instantiate_cff2_update_metrics/Cantarell-VF-ABC.retain-gids.retain-all-codepoint.wght=800.otf b/test/subset/data/expected/instantiate_cff2_update_metrics/Cantarell-VF-ABC.retain-gids.retain-all-codepoint.wght=800.otf
deleted file mode 100644
index def60cf..0000000
--- a/test/subset/data/expected/instantiate_cff2_update_metrics/Cantarell-VF-ABC.retain-gids.retain-all-codepoint.wght=800.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/instantiate_colrv1/Foldit.default.41.wght=300-600.ttf b/test/subset/data/expected/instantiate_colrv1/Foldit.default.41.wght=300-600.ttf
new file mode 100644
index 0000000..27d183f
--- /dev/null
+++ b/test/subset/data/expected/instantiate_colrv1/Foldit.default.41.wght=300-600.ttf
Binary files differ
diff --git a/test/subset/data/expected/instantiate_colrv1/Foldit.default.41.wght=900.ttf b/test/subset/data/expected/instantiate_colrv1/Foldit.default.41.wght=900.ttf
new file mode 100644
index 0000000..aae2665
--- /dev/null
+++ b/test/subset/data/expected/instantiate_colrv1/Foldit.default.41.wght=900.ttf
Binary files differ
diff --git a/test/subset/data/expected/instantiate_colrv1/Foldit.default.all.wght=300-600.ttf b/test/subset/data/expected/instantiate_colrv1/Foldit.default.all.wght=300-600.ttf
new file mode 100644
index 0000000..d3ccfdf
--- /dev/null
+++ b/test/subset/data/expected/instantiate_colrv1/Foldit.default.all.wght=300-600.ttf
Binary files differ
diff --git a/test/subset/data/expected/instantiate_colrv1/Foldit.default.retain-all-codepoint.wght=900.ttf b/test/subset/data/expected/instantiate_colrv1/Foldit.default.all.wght=900.ttf
similarity index 65%
rename from test/subset/data/expected/instantiate_colrv1/Foldit.default.retain-all-codepoint.wght=900.ttf
rename to test/subset/data/expected/instantiate_colrv1/Foldit.default.all.wght=900.ttf
index fba3a72..1e679ae 100644
--- a/test/subset/data/expected/instantiate_colrv1/Foldit.default.retain-all-codepoint.wght=900.ttf
+++ b/test/subset/data/expected/instantiate_colrv1/Foldit.default.all.wght=900.ttf
Binary files differ
diff --git a/test/subset/data/expected/instantiate_colrv1/KalniaGlaze.default.41.wght=300-600.ttf b/test/subset/data/expected/instantiate_colrv1/KalniaGlaze.default.41.wght=300-600.ttf
new file mode 100644
index 0000000..7862e82
--- /dev/null
+++ b/test/subset/data/expected/instantiate_colrv1/KalniaGlaze.default.41.wght=300-600.ttf
Binary files differ
diff --git a/test/subset/data/expected/instantiate_colrv1/KalniaGlaze.default.41.wght=900.ttf b/test/subset/data/expected/instantiate_colrv1/KalniaGlaze.default.41.wght=900.ttf
new file mode 100644
index 0000000..7741f86
--- /dev/null
+++ b/test/subset/data/expected/instantiate_colrv1/KalniaGlaze.default.41.wght=900.ttf
Binary files differ
diff --git a/test/subset/data/expected/instantiate_colrv1/KalniaGlaze.default.all.wght=300-600.ttf b/test/subset/data/expected/instantiate_colrv1/KalniaGlaze.default.all.wght=300-600.ttf
new file mode 100644
index 0000000..25e5bd1
--- /dev/null
+++ b/test/subset/data/expected/instantiate_colrv1/KalniaGlaze.default.all.wght=300-600.ttf
Binary files differ
diff --git a/test/subset/data/expected/instantiate_colrv1/KalniaGlaze.default.all.wght=900.ttf b/test/subset/data/expected/instantiate_colrv1/KalniaGlaze.default.all.wght=900.ttf
new file mode 100644
index 0000000..580816e
--- /dev/null
+++ b/test/subset/data/expected/instantiate_colrv1/KalniaGlaze.default.all.wght=900.ttf
Binary files differ
diff --git a/test/subset/data/expected/instantiate_glyf/Roboto-Variable.ABC.default.retain-all-codepoint.wght=200,wdth=90.ttf b/test/subset/data/expected/instantiate_glyf/Roboto-Variable.ABC.default.all.wght=200,wdth=90.ttf
similarity index 87%
rename from test/subset/data/expected/instantiate_glyf/Roboto-Variable.ABC.default.retain-all-codepoint.wght=200,wdth=90.ttf
rename to test/subset/data/expected/instantiate_glyf/Roboto-Variable.ABC.default.all.wght=200,wdth=90.ttf
index 190aee1..e1c5e0e 100644
--- a/test/subset/data/expected/instantiate_glyf/Roboto-Variable.ABC.default.retain-all-codepoint.wght=200,wdth=90.ttf
+++ b/test/subset/data/expected/instantiate_glyf/Roboto-Variable.ABC.default.all.wght=200,wdth=90.ttf
Binary files differ
diff --git a/test/subset/data/expected/instantiate_glyf/Roboto-Variable.ABC.default.retain-all-codepoint.wght=650,wdth=85.ttf b/test/subset/data/expected/instantiate_glyf/Roboto-Variable.ABC.default.all.wght=650,wdth=85.ttf
similarity index 87%
rename from test/subset/data/expected/instantiate_glyf/Roboto-Variable.ABC.default.retain-all-codepoint.wght=650,wdth=85.ttf
rename to test/subset/data/expected/instantiate_glyf/Roboto-Variable.ABC.default.all.wght=650,wdth=85.ttf
index 38264db..dbc663c 100644
--- a/test/subset/data/expected/instantiate_glyf/Roboto-Variable.ABC.default.retain-all-codepoint.wght=650,wdth=85.ttf
+++ b/test/subset/data/expected/instantiate_glyf/Roboto-Variable.ABC.default.all.wght=650,wdth=85.ttf
Binary files differ
diff --git a/test/subset/data/expected/instantiate_glyf/Roboto-Variable.composite.default.retain-all-codepoint.wght=200,wdth=90.ttf b/test/subset/data/expected/instantiate_glyf/Roboto-Variable.composite.default.all.wght=200,wdth=90.ttf
similarity index 91%
rename from test/subset/data/expected/instantiate_glyf/Roboto-Variable.composite.default.retain-all-codepoint.wght=200,wdth=90.ttf
rename to test/subset/data/expected/instantiate_glyf/Roboto-Variable.composite.default.all.wght=200,wdth=90.ttf
index 0fa5526..e02b6aa 100644
--- a/test/subset/data/expected/instantiate_glyf/Roboto-Variable.composite.default.retain-all-codepoint.wght=200,wdth=90.ttf
+++ b/test/subset/data/expected/instantiate_glyf/Roboto-Variable.composite.default.all.wght=200,wdth=90.ttf
Binary files differ
diff --git a/test/subset/data/expected/instantiate_glyf/Roboto-Variable.composite.default.retain-all-codepoint.wght=650,wdth=85.ttf b/test/subset/data/expected/instantiate_glyf/Roboto-Variable.composite.default.all.wght=650,wdth=85.ttf
similarity index 91%
rename from test/subset/data/expected/instantiate_glyf/Roboto-Variable.composite.default.retain-all-codepoint.wght=650,wdth=85.ttf
rename to test/subset/data/expected/instantiate_glyf/Roboto-Variable.composite.default.all.wght=650,wdth=85.ttf
index 4b07bbc..854897a 100644
--- a/test/subset/data/expected/instantiate_glyf/Roboto-Variable.composite.default.retain-all-codepoint.wght=650,wdth=85.ttf
+++ b/test/subset/data/expected/instantiate_glyf/Roboto-Variable.composite.default.all.wght=650,wdth=85.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
index ca18f67..b36e1ac 100644
--- a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
+++ b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.41,42.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.41,42.otf
index 5fe0af5..66cc5d4 100644
--- a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.41,42.otf
+++ b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.41,43.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.41,43.otf
index 29e9b9c..7ddccc6 100644
--- a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.41,43.otf
+++ b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.41.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.41.otf
index cecfb20..22e512d 100644
--- a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.41.otf
+++ b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.all.otf
similarity index 90%
rename from test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
rename to test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.all.otf
index d2507fa..cdc397e 100644
--- a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.41,42,43.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.41,42,43.otf
index dcc3e3f..7414764 100644
--- a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.41,42,43.otf
+++ b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.41,42.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.41,42.otf
index 801a547..1017805 100644
--- a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.41,42.otf
+++ b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.41,43.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.41,43.otf
index ccc8d06..e9357af 100644
--- a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.41,43.otf
+++ b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.41.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.41.otf
index 2045896..e993b67 100644
--- a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.41.otf
+++ b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.all.otf
similarity index 90%
copy from test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
copy to test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.all.otf
index d2507fa..cdc397e 100644
--- a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.retain-all-codepoint.otf
deleted file mode 100644
index d2507fa..0000000
--- a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
index 5ae5d5b..d37aca1 100644
--- a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
+++ b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,42.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,42.otf
index cfe6648..5b7cce9 100644
--- a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,42.otf
+++ b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,43.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,43.otf
index 0ec5c0b..2b64a02 100644
--- a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,43.otf
+++ b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41.otf
index 531d6e2..f1e4a05 100644
--- a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41.otf
+++ b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.all.otf
similarity index 90%
rename from test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
rename to test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.all.otf
index 0e98d1a..4c29436 100644
--- a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,42,43.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,42,43.otf
index 6530ab6..327fcc5 100644
--- a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,42,43.otf
+++ b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,42.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,42.otf
index cac1abb..6c9c50c 100644
--- a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,42.otf
+++ b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,43.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,43.otf
index 0ff1503..e218ad1 100644
--- a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,43.otf
+++ b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41.otf
index b3b1e4b..4e6c502 100644
--- a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41.otf
+++ b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.all.otf
similarity index 90%
copy from test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
copy to test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.all.otf
index 0e98d1a..4c29436 100644
--- a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.retain-all-codepoint.otf
deleted file mode 100644
index 0e98d1a..0000000
--- a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.41,42,43.otf
index 8ecfac1..6183b87 100644
--- a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.41,42,43.otf
+++ b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.41,42.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.41,42.otf
index 9969bd5..ffb232e 100644
--- a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.41,42.otf
+++ b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.41,43.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.41,43.otf
index 1072cdc..9a3620c 100644
--- a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.41,43.otf
+++ b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.41.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.41.otf
index 3a8173b..f0c3ff2 100644
--- a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.41.otf
+++ b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.all.otf
similarity index 90%
rename from test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.retain-all-codepoint.otf
rename to test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.all.otf
index fc0dcbb..ddb81ef 100644
--- a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.41,42,43.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.41,42,43.otf
index 51340dd..c6885d4 100644
--- a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.41,42,43.otf
+++ b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.41,42.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.41,42.otf
index 72cf50c..cca601f 100644
--- a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.41,42.otf
+++ b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.41,43.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.41,43.otf
index 157c302..9851c3e 100644
--- a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.41,43.otf
+++ b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.41.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.41.otf
index 662a36f..2682db9 100644
--- a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.41.otf
+++ b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.all.otf
similarity index 90%
copy from test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.retain-all-codepoint.otf
copy to test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.all.otf
index fc0dcbb..ddb81ef 100644
--- a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.retain-all-codepoint.otf
deleted file mode 100644
index fc0dcbb..0000000
--- a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.context_format2/NotoSansNewa-Regular.layout-test-retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/layout.context_format2/NotoSansNewa-Regular.layout-test-retain-gids.all.ttf
similarity index 99%
rename from test/subset/data/expected/layout.context_format2/NotoSansNewa-Regular.layout-test-retain-gids.retain-all-codepoint.ttf
rename to test/subset/data/expected/layout.context_format2/NotoSansNewa-Regular.layout-test-retain-gids.all.ttf
index c2ef8fe..3a9398d 100644
--- a/test/subset/data/expected/layout.context_format2/NotoSansNewa-Regular.layout-test-retain-gids.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.context_format2/NotoSansNewa-Regular.layout-test-retain-gids.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.context_format2/NotoSansNewa-Regular.layout-test-retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/layout.context_format2/NotoSansNewa-Regular.layout-test.all.ttf
similarity index 99%
copy from test/subset/data/expected/layout.context_format2/NotoSansNewa-Regular.layout-test-retain-gids.retain-all-codepoint.ttf
copy to test/subset/data/expected/layout.context_format2/NotoSansNewa-Regular.layout-test.all.ttf
index c2ef8fe..3a9398d 100644
--- a/test/subset/data/expected/layout.context_format2/NotoSansNewa-Regular.layout-test-retain-gids.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.context_format2/NotoSansNewa-Regular.layout-test.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.context_format2/NotoSansNewa-Regular.layout-test.retain-all-codepoint.ttf b/test/subset/data/expected/layout.context_format2/NotoSansNewa-Regular.layout-test.retain-all-codepoint.ttf
deleted file mode 100644
index c2ef8fe..0000000
--- a/test/subset/data/expected/layout.context_format2/NotoSansNewa-Regular.layout-test.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.drop_feature/SpectralSC-ExtraLightItalic.default.retain-all-codepoint.ttf b/test/subset/data/expected/layout.drop_feature/SpectralSC-ExtraLightItalic.default.all.ttf
similarity index 99%
rename from test/subset/data/expected/layout.drop_feature/SpectralSC-ExtraLightItalic.default.retain-all-codepoint.ttf
rename to test/subset/data/expected/layout.drop_feature/SpectralSC-ExtraLightItalic.default.all.ttf
index 7dcb3ec..4f0453e 100644
--- a/test/subset/data/expected/layout.drop_feature/SpectralSC-ExtraLightItalic.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.drop_feature/SpectralSC-ExtraLightItalic.default.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.drop_feature/SpectralSC-ExtraLightItalic.glyph-names.retain-all-codepoint.ttf b/test/subset/data/expected/layout.drop_feature/SpectralSC-ExtraLightItalic.glyph-names.all.ttf
similarity index 99%
rename from test/subset/data/expected/layout.drop_feature/SpectralSC-ExtraLightItalic.glyph-names.retain-all-codepoint.ttf
rename to test/subset/data/expected/layout.drop_feature/SpectralSC-ExtraLightItalic.glyph-names.all.ttf
index f17c609..f49b361 100644
--- a/test/subset/data/expected/layout.drop_feature/SpectralSC-ExtraLightItalic.glyph-names.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.drop_feature/SpectralSC-ExtraLightItalic.glyph-names.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.drop_feature/SpectralSC-ExtraLightItalic.notdef-outline.retain-all-codepoint.ttf b/test/subset/data/expected/layout.drop_feature/SpectralSC-ExtraLightItalic.notdef-outline.all.ttf
similarity index 99%
rename from test/subset/data/expected/layout.drop_feature/SpectralSC-ExtraLightItalic.notdef-outline.retain-all-codepoint.ttf
rename to test/subset/data/expected/layout.drop_feature/SpectralSC-ExtraLightItalic.notdef-outline.all.ttf
index 490ab70..17bf19b 100644
--- a/test/subset/data/expected/layout.drop_feature/SpectralSC-ExtraLightItalic.notdef-outline.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.drop_feature/SpectralSC-ExtraLightItalic.notdef-outline.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.default.retain-all-codepoint.ttf b/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.default.all.ttf
similarity index 99%
rename from test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.default.retain-all-codepoint.ttf
rename to test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.default.all.ttf
index c590621..16cb5f0 100644
--- a/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.default.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.glyph-names.retain-all-codepoint.ttf b/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.glyph-names.all.ttf
similarity index 99%
rename from test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.glyph-names.retain-all-codepoint.ttf
rename to test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.glyph-names.all.ttf
index 97948b0..1c7c75c 100644
--- a/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.glyph-names.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.glyph-names.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.default.retain-all-codepoint.ttf b/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.notdef-outline.all.ttf
similarity index 99%
copy from test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.default.retain-all-codepoint.ttf
copy to test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.notdef-outline.all.ttf
index c590621..16cb5f0 100644
--- a/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.notdef-outline.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.notdef-outline.retain-all-codepoint.ttf b/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.notdef-outline.retain-all-codepoint.ttf
deleted file mode 100644
index c590621..0000000
--- a/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.notdef-outline.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.empty_ligature_offset/AnekBangla-latin-subset.default.all.ttf b/test/subset/data/expected/layout.empty_ligature_offset/AnekBangla-latin-subset.default.all.ttf
new file mode 100644
index 0000000..9521893
--- /dev/null
+++ b/test/subset/data/expected/layout.empty_ligature_offset/AnekBangla-latin-subset.default.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.retain-all-codepoint.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.all.ttf
similarity index 100%
rename from test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.retain-all-codepoint.ttf
rename to test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.retain-all-codepoint.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.all.ttf
similarity index 100%
rename from test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.retain-all-codepoint.ttf
rename to test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.retain-all-codepoint.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.all.ttf
similarity index 100%
copy from test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.retain-all-codepoint.ttf
copy to test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.retain-all-codepoint.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.retain-all-codepoint.ttf
deleted file mode 100644
index c64ef97..0000000
--- a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,42,43,57.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,42,43,57.otf
index 428bf0f..7e588f6 100644
--- a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,42,43,57.otf
+++ b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,42,43,57.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,42,43.otf
index 81ff828..ef45cb7 100644
--- a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,42,43.otf
+++ b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,42.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,42.otf
index 46db5bb..50f9b56 100644
--- a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,42.otf
+++ b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,56,57.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,56,57.otf
index f3ae184..dfb3386 100644
--- a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,56,57.otf
+++ b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,56,57.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41.otf
index c484821..902123e 100644
--- a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41.otf
+++ b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.42,57.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.42,57.otf
index 0dfcfc4..b39a657 100644
--- a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.42,57.otf
+++ b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.42,57.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,42,43,57.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,42,43,57.otf
index f7b7a36..9a750f2 100644
--- a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,42,43,57.otf
+++ b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,42,43,57.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,42,43.otf
index 294bfad..65f12cd 100644
--- a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,42,43.otf
+++ b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,42.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,42.otf
index 8c2c8da..af88075 100644
--- a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,42.otf
+++ b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,56,57.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,56,57.otf
index 8f454b7..fab502e 100644
--- a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,56,57.otf
+++ b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,56,57.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41.otf
index bea2117..adf3f29 100644
--- a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41.otf
+++ b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.42,57.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.42,57.otf
index 8419d4e..eb827d7 100644
--- a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.42,57.otf
+++ b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.42,57.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.default.retain-all-codepoint.ttf b/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.default.all.ttf
similarity index 100%
rename from test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.default.retain-all-codepoint.ttf
rename to test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.default.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.drop-hints.retain-all-codepoint.ttf b/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.drop-hints.all.ttf
similarity index 100%
rename from test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.drop-hints.retain-all-codepoint.ttf
rename to test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.drop-hints.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.retain-gids.all.ttf
similarity index 100%
rename from test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.retain-gids.retain-all-codepoint.ttf
rename to test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.retain-gids.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.default.1E00,303.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.default.1E00,303.ttf
index 863fce8..f0a4b60 100644
--- a/test/subset/data/expected/layout.gdef/Roboto-Regular.default.1E00,303.ttf
+++ b/test/subset/data/expected/layout.gdef/Roboto-Regular.default.1E00,303.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.default.303.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.default.303.ttf
index efc3e47..e27b6d8 100644
--- a/test/subset/data/expected/layout.gdef/Roboto-Regular.default.303.ttf
+++ b/test/subset/data/expected/layout.gdef/Roboto-Regular.default.303.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.default.309,20,30F.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.default.309,20,30F.ttf
index 9d794ef..17e7650 100644
--- a/test/subset/data/expected/layout.gdef/Roboto-Regular.default.309,20,30F.ttf
+++ b/test/subset/data/expected/layout.gdef/Roboto-Regular.default.309,20,30F.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.default.323.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.default.323.ttf
index e1d1605..9d8035e 100644
--- a/test/subset/data/expected/layout.gdef/Roboto-Regular.default.323.ttf
+++ b/test/subset/data/expected/layout.gdef/Roboto-Regular.default.323.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.default.41,42,43.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.default.41,42,43.ttf
index 1f5721d..32fd97c 100644
--- a/test/subset/data/expected/layout.gdef/Roboto-Regular.default.41,42,43.ttf
+++ b/test/subset/data/expected/layout.gdef/Roboto-Regular.default.41,42,43.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.1E00,303.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.1E00,303.ttf
index 0a8dcb0..0c9b8f4 100644
--- a/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.1E00,303.ttf
+++ b/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.1E00,303.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.303.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.303.ttf
index b3fc9df..2c2a416 100644
--- a/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.303.ttf
+++ b/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.303.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.309,20,30F.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.309,20,30F.ttf
index d553a87..bb99451 100644
--- a/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.309,20,30F.ttf
+++ b/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.309,20,30F.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.323.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.323.ttf
index edaadc5..11a1cb5 100644
--- a/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.323.ttf
+++ b/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.323.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.41,42,43.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.41,42,43.ttf
index 7098c08..5311019 100644
--- a/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.41,42,43.ttf
+++ b/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.41,42,43.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.1E00,303.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.1E00,303.ttf
index 863fce8..f0a4b60 100644
--- a/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.1E00,303.ttf
+++ b/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.1E00,303.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.303.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.303.ttf
index efc3e47..e27b6d8 100644
--- a/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.303.ttf
+++ b/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.303.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.309,20,30F.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.309,20,30F.ttf
index 9d794ef..17e7650 100644
--- a/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.309,20,30F.ttf
+++ b/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.309,20,30F.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.323.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.323.ttf
index e1d1605..9d8035e 100644
--- a/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.323.ttf
+++ b/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.323.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.41,42,43.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.41,42,43.ttf
index 1f5721d..32fd97c 100644
--- a/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.41,42,43.ttf
+++ b/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.41,42,43.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.41,43.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.41,43.otf
index 1e59c75..f7e2365 100644
--- a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.41,43.otf
+++ b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.41,46.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.41,46.otf
index 67d882b..436b29c 100644
--- a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.41,46.otf
+++ b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.41,46.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.41.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.41.otf
index 77ab03a..b503bad 100644
--- a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.41.otf
+++ b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.42,44.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.42,44.otf
index 35f81e5..4cdeb83 100644
--- a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.42,44.otf
+++ b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.42,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.43,46.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.43,46.otf
index 148c9ca..f42611e 100644
--- a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.43,46.otf
+++ b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.43,46.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.all.otf
similarity index 89%
rename from test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.retain-all-codepoint.otf
rename to test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.all.otf
index 24f1c46..48c83bc 100644
--- a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.41,43.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.41,43.otf
index 21a9b63..02650c3 100644
--- a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.41,43.otf
+++ b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.41,46.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.41,46.otf
index 78e4ab8..b7c34e9 100644
--- a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.41,46.otf
+++ b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.41,46.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.41.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.41.otf
index 8a17ae6..11b7c12 100644
--- a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.41.otf
+++ b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.42,44.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.42,44.otf
index 6bb5293..9514236 100644
--- a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.42,44.otf
+++ b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.42,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.43,46.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.43,46.otf
index 354ace8..c812204 100644
--- a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.43,46.otf
+++ b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.43,46.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.all.otf
similarity index 89%
copy from test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.retain-all-codepoint.otf
copy to test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.all.otf
index 24f1c46..48c83bc 100644
--- a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.retain-all-codepoint.otf
deleted file mode 100644
index 24f1c46..0000000
--- a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.21,23,25.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.21,23,25.otf
index e56914e..93cfbd6 100644
--- a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.21,23,25.otf
+++ b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.21,23,25.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.21,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.21,23.otf
index 3c6c260..0d018a7 100644
--- a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.21,23.otf
+++ b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.21,23.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.2E,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.2E,23.otf
index 2250037..13eea67 100644
--- a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.2E,23.otf
+++ b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.2E,23.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.41,42,43.otf
index e32d342..b54481f 100644
--- a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.41,42,43.otf
+++ b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.all.otf
similarity index 89%
rename from test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.retain-all-codepoint.otf
rename to test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.all.otf
index a047174..8874c5e 100644
--- a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.21,23,25.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.21,23,25.otf
index 99f8761..ffd26c0 100644
--- a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.21,23,25.otf
+++ b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.21,23,25.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.21,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.21,23.otf
index 2fc6e5f..ba316f7 100644
--- a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.21,23.otf
+++ b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.21,23.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.2E,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.2E,23.otf
index e7dead8..683aafb 100644
--- a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.2E,23.otf
+++ b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.2E,23.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.41,42,43.otf
index 969d156..ad0559e 100644
--- a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.41,42,43.otf
+++ b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.all.otf
similarity index 89%
copy from test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.retain-all-codepoint.otf
copy to test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.all.otf
index a047174..8874c5e 100644
--- a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.retain-all-codepoint.otf
deleted file mode 100644
index a047174..0000000
--- a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.21,23,25.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.21,23,25.otf
index 2c67f99..46e100c 100644
--- a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.21,23,25.otf
+++ b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.21,23,25.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.21,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.21,23.otf
index 267bec4..4a5bfc9 100644
--- a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.21,23.otf
+++ b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.21,23.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.2E,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.2E,23.otf
index ee13a7f..6bafd4a 100644
--- a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.2E,23.otf
+++ b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.2E,23.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.41,42,43.otf
index b2ec05c..39d0432 100644
--- a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.41,42,43.otf
+++ b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.all.otf
similarity index 89%
rename from test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.retain-all-codepoint.otf
rename to test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.all.otf
index b9c03f0..e41a6d0 100644
--- a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.21,23,25.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.21,23,25.otf
index 693e784..225c32c 100644
--- a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.21,23,25.otf
+++ b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.21,23,25.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.21,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.21,23.otf
index 2c0626a..3837698 100644
--- a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.21,23.otf
+++ b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.21,23.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.2E,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.2E,23.otf
index bac77bb..fc81cd4 100644
--- a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.2E,23.otf
+++ b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.2E,23.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.41,42,43.otf
index 82d4b3a..16a47a0 100644
--- a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.41,42,43.otf
+++ b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.all.otf
similarity index 89%
copy from test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.retain-all-codepoint.otf
copy to test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.all.otf
index b9c03f0..e41a6d0 100644
--- a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.retain-all-codepoint.otf
deleted file mode 100644
index b9c03f0..0000000
--- a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.28,29.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.28,29.otf
index 4784f61..822644b 100644
--- a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.28,29.otf
+++ b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.28,29.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.28,2B.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.28,2B.otf
index 25ab8a0..48ac39e 100644
--- a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.28,2B.otf
+++ b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.28,2B.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.29,2B.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.29,2B.otf
index f6225b2..628cc38 100644
--- a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.29,2B.otf
+++ b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.29,2B.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.41,42,43.otf
index 2742c80..49f314f 100644
--- a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.41,42,43.otf
+++ b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.all.otf
similarity index 90%
rename from test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.retain-all-codepoint.otf
rename to test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.all.otf
index 308dcb8..aa80f26 100644
--- a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.28,29.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.28,29.otf
index 1111175..4a46a2e 100644
--- a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.28,29.otf
+++ b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.28,29.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.28,2B.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.28,2B.otf
index a0f56c9..7dbb142 100644
--- a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.28,2B.otf
+++ b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.28,2B.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.29,2B.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.29,2B.otf
index 9e882c1..fa6f8c6 100644
--- a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.29,2B.otf
+++ b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.29,2B.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.41,42,43.otf
index c7a4eb4..82edd8d 100644
--- a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.41,42,43.otf
+++ b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.all.otf
similarity index 90%
copy from test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.retain-all-codepoint.otf
copy to test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.all.otf
index 308dcb8..aa80f26 100644
--- a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.retain-all-codepoint.otf
deleted file mode 100644
index 308dcb8..0000000
--- a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,42,43,44.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,42,43,44.otf
index af2af9f..5fdb8dc 100644
--- a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,42,43,44.otf
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,42,43,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,42,43,45.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,42,43,45.otf
index 9a74dd1..c7cab4a 100644
--- a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,42,43,45.otf
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,42,43,45.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,42,43.otf
index 2c72bad..d7e081f 100644
--- a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,42,43.otf
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,42.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,42.otf
index dab6fdd..222e59a 100644
--- a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,42.otf
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,43,44,45,46.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,43,44,45,46.otf
index 9c0853b..ad9ee3d 100644
--- a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,43,44,45,46.otf
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,43,44,45,46.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,43,44.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,43,44.otf
index 5f57975..144c327 100644
--- a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,43,44.otf
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,43,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,43,45.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,43,45.otf
index 3dcc084..b58b566 100644
--- a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,43,45.otf
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,43,45.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,43.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,43.otf
index ada1a54..405774e 100644
--- a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,43.otf
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41.otf
index 656c6e3..b34e4da 100644
--- a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41.otf
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.all.otf
similarity index 90%
rename from test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.retain-all-codepoint.otf
rename to test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.all.otf
index 8dd5444..972a7ad 100644
--- a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,42,43,44.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,42,43,44.otf
index 58889d6..75a6c16 100644
--- a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,42,43,44.otf
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,42,43,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,42,43,45.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,42,43,45.otf
index 8c0c211..cea9c9b 100644
--- a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,42,43,45.otf
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,42,43,45.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,42,43.otf
index 3aff353..24483e9 100644
--- a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,42,43.otf
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,42.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,42.otf
index cb75819..7bbb216 100644
--- a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,42.otf
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,43,44,45,46.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,43,44,45,46.otf
index 9776758..92648a2 100644
--- a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,43,44,45,46.otf
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,43,44,45,46.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,43,44.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,43,44.otf
index bc06070..ed4995f 100644
--- a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,43,44.otf
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,43,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,43,45.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,43,45.otf
index 3d87498..23818e5 100644
--- a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,43,45.otf
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,43,45.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,43.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,43.otf
index fc99dd8..164a686 100644
--- a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,43.otf
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41.otf
index 6395a87..9e3e97a 100644
--- a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41.otf
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.all.otf
similarity index 90%
copy from test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.retain-all-codepoint.otf
copy to test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.all.otf
index 8dd5444..972a7ad 100644
--- a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.retain-all-codepoint.otf
deleted file mode 100644
index 8dd5444..0000000
--- a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,43,44.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,43,44.otf
index 0313313..08a9e79 100644
--- a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,43,44.otf
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,43,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,43,45.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,43,45.otf
index 99116b4..16c005f 100644
--- a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,43,45.otf
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,43,45.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,43.otf
index 564d0c5..2c38101 100644
--- a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,43.otf
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,44.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,44.otf
index 1dcc5bd..fc0ace6 100644
--- a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,44.otf
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,45.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,45.otf
index 9c330c7..f4c0d68 100644
--- a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,45.otf
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,45.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42.otf
index 1965933..4209d4f 100644
--- a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42.otf
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,43.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,43.otf
index 8ee98e9..dee858a 100644
--- a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,43.otf
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41.otf
index 10c7629..91b88a1 100644
--- a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41.otf
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.42.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.42.otf
index f7e92d6..2ab008a 100644
--- a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.42.otf
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.all.otf
similarity index 91%
rename from test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.retain-all-codepoint.otf
rename to test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.all.otf
index 32ffff9..2846527 100644
--- a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,43,44.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,43,44.otf
index 6ff7711..9f12f0f 100644
--- a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,43,44.otf
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,43,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,43,45.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,43,45.otf
index bf8265e..b9e32c9 100644
--- a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,43,45.otf
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,43,45.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,43.otf
index 8f41e96..d11ec14 100644
--- a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,43.otf
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,44.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,44.otf
index 63d5b1a..8560125 100644
--- a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,44.otf
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,45.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,45.otf
index 2d5de06..50d348c 100644
--- a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,45.otf
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,45.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42.otf
index aecd96a..3bc08c5 100644
--- a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42.otf
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,43.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,43.otf
index 19b6c7b..ecfea74 100644
--- a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,43.otf
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41.otf
index 81b6196..c04ae6c 100644
--- a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41.otf
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.42.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.42.otf
index 4ac9a09..50b4321 100644
--- a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.42.otf
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.all.otf
similarity index 91%
copy from test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.retain-all-codepoint.otf
copy to test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.all.otf
index 32ffff9..2846527 100644
--- a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.retain-all-codepoint.otf
deleted file mode 100644
index 32ffff9..0000000
--- a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,42,43,44.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,42,43,44.otf
index 8f46239..7e0f892 100644
--- a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,42,43,44.otf
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,42,43,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,42,43,45.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,42,43,45.otf
index e1ae2bc..ee7a678 100644
--- a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,42,43,45.otf
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,42,43,45.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,42,43.otf
index 42b332e..b6e35de 100644
--- a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,42,43.otf
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,42.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,42.otf
index 8028c9d..fbff369 100644
--- a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,42.otf
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,43,44,45,46.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,43,44,45,46.otf
index 3e9f1e7..e6f4fcb 100644
--- a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,43,44,45,46.otf
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,43,44,45,46.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,43,44.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,43,44.otf
index ea47831..7f58d83 100644
--- a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,43,44.otf
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,43,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,43,45.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,43,45.otf
index 79206e8..77ae76c 100644
--- a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,43,45.otf
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,43,45.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,43.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,43.otf
index db066b7..f9d27f8 100644
--- a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,43.otf
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41.otf
index 7019ee3..53915e3 100644
--- a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41.otf
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.all.otf
similarity index 90%
rename from test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.retain-all-codepoint.otf
rename to test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.all.otf
index 59c911d..910866c 100644
--- a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,42,43,44.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,42,43,44.otf
index b4d50a9..7761d5c 100644
--- a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,42,43,44.otf
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,42,43,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,42,43,45.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,42,43,45.otf
index e39e1b9..f793b3c 100644
--- a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,42,43,45.otf
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,42,43,45.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,42,43.otf
index a328c7e..8315630 100644
--- a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,42,43.otf
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,42.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,42.otf
index 5b6424a..4276d0f 100644
--- a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,42.otf
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,43,44,45,46.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,43,44,45,46.otf
index 21b1983..9bc0923 100644
--- a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,43,44,45,46.otf
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,43,44,45,46.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,43,44.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,43,44.otf
index c23f81b..69cf3f4 100644
--- a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,43,44.otf
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,43,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,43,45.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,43,45.otf
index 69b2e46..cdd3aae 100644
--- a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,43,45.otf
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,43,45.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,43.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,43.otf
index d533fa0..7ac49df 100644
--- a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,43.otf
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41.otf
index 3cbf9fd..899a1bd 100644
--- a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41.otf
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.all.otf
similarity index 90%
copy from test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.retain-all-codepoint.otf
copy to test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.all.otf
index 59c911d..910866c 100644
--- a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.retain-all-codepoint.otf
deleted file mode 100644
index 59c911d..0000000
--- a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test-retain-gids.30,31,32,33.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test-retain-gids.30,31,32,33.otf
index 445f567..abc798d 100644
--- a/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test-retain-gids.30,31,32,33.otf
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test-retain-gids.30,31,32,33.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
index 456575a..e792023 100644
--- a/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test-retain-gids.all.otf
similarity index 89%
rename from test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
rename to test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test-retain-gids.all.otf
index f1d3e43..d36b832 100644
--- a/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test-retain-gids.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test.30,31,32,33.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test.30,31,32,33.otf
index bc47f58..1c24eac 100644
--- a/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test.30,31,32,33.otf
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test.30,31,32,33.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test.41,42,43.otf
index babb9d5..a19fb22 100644
--- a/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test.41,42,43.otf
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test.all.otf
similarity index 89%
copy from test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
copy to test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test.all.otf
index f1d3e43..d36b832 100644
--- a/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test.retain-all-codepoint.otf
deleted file mode 100644
index f1d3e43..0000000
--- a/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test-retain-gids.30,31,32,33.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test-retain-gids.30,31,32,33.otf
index 77f9ce0..fc11d5e 100644
--- a/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test-retain-gids.30,31,32,33.otf
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test-retain-gids.30,31,32,33.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
index 60bf6f0..1eca1f2 100644
--- a/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test-retain-gids.all.otf
similarity index 91%
rename from test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
rename to test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test-retain-gids.all.otf
index 7d4dea0..34ea5de 100644
--- a/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test-retain-gids.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test.30,31,32,33.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test.30,31,32,33.otf
index e57101a..52df3f4 100644
--- a/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test.30,31,32,33.otf
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test.30,31,32,33.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test.41,42,43.otf
index 41bc343..7d2e00b 100644
--- a/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test.41,42,43.otf
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test.all.otf
similarity index 91%
copy from test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
copy to test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test.all.otf
index 7d4dea0..34ea5de 100644
--- a/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test.retain-all-codepoint.otf
deleted file mode 100644
index 7d4dea0..0000000
--- a/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test-retain-gids.30,31,32,33.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test-retain-gids.30,31,32,33.otf
index 09452d9..df37e4b 100644
--- a/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test-retain-gids.30,31,32,33.otf
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test-retain-gids.30,31,32,33.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test-retain-gids.41,42,43.otf
index 66edc45..6c645f5 100644
--- a/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test-retain-gids.41,42,43.otf
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test-retain-gids.all.otf
similarity index 90%
rename from test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test-retain-gids.retain-all-codepoint.otf
rename to test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test-retain-gids.all.otf
index 554fb54..0cce179 100644
--- a/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test-retain-gids.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test.30,31,32,33.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test.30,31,32,33.otf
index f72d0cc..36fa3d7 100644
--- a/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test.30,31,32,33.otf
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test.30,31,32,33.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test.41,42,43.otf
index 33abe62..2a3995a 100644
--- a/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test.41,42,43.otf
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test.all.otf
similarity index 90%
copy from test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test-retain-gids.retain-all-codepoint.otf
copy to test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test.all.otf
index 554fb54..0cce179 100644
--- a/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test.retain-all-codepoint.otf
deleted file mode 100644
index 554fb54..0000000
--- a/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test-retain-gids.41,42.otf b/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test-retain-gids.41,42.otf
index c382ed2..961ce15 100644
--- a/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test-retain-gids.41,42.otf
+++ b/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test-retain-gids.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test-retain-gids.41.otf b/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test-retain-gids.41.otf
index 0ff63b9..b08c157 100644
--- a/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test-retain-gids.41.otf
+++ b/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test-retain-gids.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test-retain-gids.42.otf b/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test-retain-gids.42.otf
index 7981553..1167682 100644
--- a/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test-retain-gids.42.otf
+++ b/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test-retain-gids.42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test.41,42.otf b/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test.41,42.otf
index f2406c5..536c86b 100644
--- a/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test.41,42.otf
+++ b/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test.41.otf b/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test.41.otf
index 32f8025..9eea578 100644
--- a/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test.41.otf
+++ b/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test.42.otf b/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test.42.otf
index da45812..9515545 100644
--- a/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test.42.otf
+++ b/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test.42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test-retain-gids.53A9,53F1.otf b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test-retain-gids.53A9,53F1.otf
index 9a58fee..87ada26 100644
--- a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test-retain-gids.53A9,53F1.otf
+++ b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test-retain-gids.53A9,53F1.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test-retain-gids.53A9.otf b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test-retain-gids.53A9.otf
index c5c9146..42464f3 100644
--- a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test-retain-gids.53A9.otf
+++ b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test-retain-gids.53A9.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test-retain-gids.53F1.otf b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test-retain-gids.53F1.otf
index 1b11e10..009db72 100644
--- a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test-retain-gids.53F1.otf
+++ b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test-retain-gids.53F1.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test-retain-gids.all.otf
similarity index 94%
rename from test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test-retain-gids.retain-all-codepoint.otf
rename to test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test-retain-gids.all.otf
index 7249c5a..6def691 100644
--- a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test-retain-gids.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test.53A9,53F1.otf b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test.53A9,53F1.otf
index 91357c9..1a4f65f 100644
--- a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test.53A9,53F1.otf
+++ b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test.53A9,53F1.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test.53A9.otf b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test.53A9.otf
index df08b73..c1cd42c 100644
--- a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test.53A9.otf
+++ b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test.53A9.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test.53F1.otf b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test.53F1.otf
index 39da89b..688005a 100644
--- a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test.53F1.otf
+++ b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test.53F1.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test.all.otf
similarity index 94%
rename from test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test.retain-all-codepoint.otf
rename to test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test.all.otf
index 51afa40..d7c4fb1 100644
--- a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.41,42,43.otf
index ed8a98b..5449dbe 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.41,42,43.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.41,42.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.41,42.otf
index 33c8824..79d2f27 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.41,42.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.41,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.41,43.otf
index 8148021..2238508 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.41,43.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.41.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.41.otf
index 24e6b78..8613de6 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.41.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.all.otf
similarity index 90%
rename from test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.retain-all-codepoint.otf
rename to test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.all.otf
index 0ff250b..4e288c0 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.41,42,43.otf
index bde0da1..e3b665c 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.41,42,43.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.41,42.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.41,42.otf
index d34cc87..6a66529 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.41,42.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.41,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.41,43.otf
index e62f795..99f7a2f 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.41,43.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.41.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.41.otf
index 649e446..c423502 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.41.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.all.otf
similarity index 90%
copy from test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.retain-all-codepoint.otf
copy to test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.all.otf
index 0ff250b..4e288c0 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.retain-all-codepoint.otf
deleted file mode 100644
index 0ff250b..0000000
--- a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,42,43.otf
index f6b78bc..c8a57a4 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,42,43.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,42.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,42.otf
index 6f2e7ef..4e6d68d 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,42.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,43.otf
index 27b29e5..1451c93 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,43.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41.otf
index f4fa0e9..c5e1cb6 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.all.otf
similarity index 90%
rename from test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.retain-all-codepoint.otf
rename to test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.all.otf
index ff0595a..e1f6791 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,42,43.otf
index 8086051..798ff4f 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,42,43.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,42.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,42.otf
index 0a26e0f..990e576 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,42.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,43.otf
index f4a46ef..53203ae 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,43.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41.otf
index 00d4707..d2c3c35 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.all.otf
similarity index 90%
copy from test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.retain-all-codepoint.otf
copy to test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.all.otf
index ff0595a..e1f6791 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.retain-all-codepoint.otf
deleted file mode 100644
index ff0595a..0000000
--- a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.41,42,43.otf
index bfe6624..02fa890 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.41,42,43.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.41,42.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.41,42.otf
index 808ba68..87f2bb0 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.41,42.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.41,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.41,43.otf
index 5bb167e..8b00a06 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.41,43.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.41.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.41.otf
index 8844949..dd17a91 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.41.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.all.otf
similarity index 90%
rename from test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.retain-all-codepoint.otf
rename to test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.all.otf
index a012ff1..9f43596 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.41,42,43.otf
index a00ab82..d124834 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.41,42,43.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.41,42.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.41,42.otf
index 0cfcad6..313f14a 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.41,42.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.41,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.41,43.otf
index 3d96d48..33277fa 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.41,43.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.41.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.41.otf
index 51c6316..89d08d5 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.41.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.all.otf
similarity index 90%
copy from test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.retain-all-codepoint.otf
copy to test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.all.otf
index a012ff1..9f43596 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.retain-all-codepoint.otf
deleted file mode 100644
index a012ff1..0000000
--- a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5_format2/Molengo-Regular.layout-test-retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/layout.gsub5_format2/Molengo-Regular.layout-test-retain-gids.all.ttf
similarity index 100%
rename from test/subset/data/expected/layout.gsub5_format2/Molengo-Regular.layout-test-retain-gids.retain-all-codepoint.ttf
rename to test/subset/data/expected/layout.gsub5_format2/Molengo-Regular.layout-test-retain-gids.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5_format2/Molengo-Regular.layout-test.retain-all-codepoint.ttf b/test/subset/data/expected/layout.gsub5_format2/Molengo-Regular.layout-test.all.ttf
similarity index 100%
rename from test/subset/data/expected/layout.gsub5_format2/Molengo-Regular.layout-test.retain-all-codepoint.ttf
rename to test/subset/data/expected/layout.gsub5_format2/Molengo-Regular.layout-test.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test-retain-gids.30,31,32,33.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test-retain-gids.30,31,32,33.otf
index c38bb18..abf92b0 100644
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test-retain-gids.30,31,32,33.otf
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test-retain-gids.30,31,32,33.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
index ea05697..5986a8a 100644
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test-retain-gids.all.otf
similarity index 90%
rename from test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
rename to test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test-retain-gids.all.otf
index be5c742..f575821 100644
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test-retain-gids.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test.30,31,32,33.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test.30,31,32,33.otf
index 9c6cf18..a43c055 100644
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test.30,31,32,33.otf
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test.30,31,32,33.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test.41,42,43.otf
index e5e4cfb..0982534 100644
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test.41,42,43.otf
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test.all.otf
similarity index 90%
copy from test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
copy to test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test.all.otf
index be5c742..f575821 100644
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test.retain-all-codepoint.otf
deleted file mode 100644
index be5c742..0000000
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test-retain-gids.30,31,32,33.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test-retain-gids.30,31,32,33.otf
index e5b9d6e..9c32e5b 100644
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test-retain-gids.30,31,32,33.otf
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test-retain-gids.30,31,32,33.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
index dcf5a16..1cb5837 100644
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test-retain-gids.all.otf
similarity index 90%
rename from test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
rename to test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test-retain-gids.all.otf
index 3072df6..10926d0 100644
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test-retain-gids.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test.30,31,32,33.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test.30,31,32,33.otf
index ef1bc2d..aa20ef7 100644
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test.30,31,32,33.otf
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test.30,31,32,33.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test.41,42,43.otf
index f89f5b8..c5bb7a8 100644
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test.41,42,43.otf
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test.all.otf
similarity index 90%
copy from test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
copy to test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test.all.otf
index 3072df6..10926d0 100644
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test.retain-all-codepoint.otf
deleted file mode 100644
index 3072df6..0000000
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test-retain-gids.30,31,32,33.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test-retain-gids.30,31,32,33.otf
index eb573b0..d57b1d5 100644
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test-retain-gids.30,31,32,33.otf
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test-retain-gids.30,31,32,33.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test-retain-gids.41,42,43.otf
index f5dd384..5055ba5 100644
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test-retain-gids.41,42,43.otf
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test-retain-gids.all.otf
similarity index 90%
rename from test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test-retain-gids.retain-all-codepoint.otf
rename to test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test-retain-gids.all.otf
index 73d92d4..210c0e0 100644
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test-retain-gids.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test.30,31,32,33.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test.30,31,32,33.otf
index 16d2b34..b7d7d1f 100644
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test.30,31,32,33.otf
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test.30,31,32,33.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test.41,42,43.otf
index 6623508..8da4abc 100644
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test.41,42,43.otf
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test.all.otf
similarity index 90%
copy from test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test-retain-gids.retain-all-codepoint.otf
copy to test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test.all.otf
index 73d92d4..210c0e0 100644
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test.retain-all-codepoint.otf
deleted file mode 100644
index 73d92d4..0000000
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46,47,48,49.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46,47,48,49.otf
index 4e0b307..bdf6761 100644
--- a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46,47,48,49.otf
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46,47,48,49.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46,47.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46,47.otf
index 28bc409..9635c03 100644
--- a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46,47.otf
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46,47.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46,4D.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46,4D.otf
index 90e1cdf..5451ee5 100644
--- a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46,4D.otf
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46,4D.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46,51.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46,51.otf
index 1b07a7a..d88fa48 100644
--- a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46,51.otf
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46,51.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46.otf
index ef2bd57..c843465 100644
--- a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46.otf
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43.otf
index ecc3c41..36439e3 100644
--- a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43.otf
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41.otf
index eb60c6b..85d6da8 100644
--- a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41.otf
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.61.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.61.otf
index 275b11b..49084a4 100644
--- a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.61.otf
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.61.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.all.otf
similarity index 91%
rename from test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.retain-all-codepoint.otf
rename to test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.all.otf
index d29304c..8374d71 100644
--- a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46,47,48,49.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46,47,48,49.otf
index f149bbf..04a6aa7 100644
--- a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46,47,48,49.otf
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46,47,48,49.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46,47.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46,47.otf
index 3475f4e..54d0d1d 100644
--- a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46,47.otf
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46,47.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46,4D.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46,4D.otf
index 8e8c4de..31ce478 100644
--- a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46,4D.otf
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46,4D.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46,51.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46,51.otf
index cd519a5..669a656 100644
--- a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46,51.otf
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46,51.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46.otf
index 063ac99..3df16da 100644
--- a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46.otf
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43.otf
index 9ee6ccf..d376131 100644
--- a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43.otf
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41.otf
index 0cb632a..e7992c9 100644
--- a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41.otf
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.61.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.61.otf
index ec09bf0..4607914 100644
--- a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.61.otf
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.61.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.all.otf
similarity index 91%
copy from test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.retain-all-codepoint.otf
copy to test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.all.otf
index d29304c..8374d71 100644
--- a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.all.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.retain-all-codepoint.otf
deleted file mode 100644
index d29304c..0000000
--- a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.retain-all-codepoint.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.all.ttf
similarity index 99%
rename from test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.retain-all-codepoint.ttf
rename to test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.all.ttf
index a49c63e..1c295de 100644
--- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.retain-all-codepoint.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.all.ttf
similarity index 99%
copy from test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.retain-all-codepoint.ttf
copy to test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.all.ttf
index a49c63e..1c295de 100644
--- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.retain-all-codepoint.ttf
deleted file mode 100644
index a49c63e..0000000
--- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644,623,62D,644,627,645,2E.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644,623,62D,644,627,645,2E.ttf
index 7d58b3c..121caa0 100644
--- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644,623,62D,644,627,645,2E.ttf
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644,623,62D,644,627,645,2E.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644,62D,628.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644,62D,628.ttf
index e402e57..15d86cc 100644
--- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644,62D,628.ttf
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644,62D,628.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644.ttf
index 17ad7cd..a1b2f45 100644
--- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644.ttf
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.633,645,627,621,20,644,627.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.633,645,627,621,20,644,627.ttf
index 29166f7..24c717b 100644
--- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.633,645,627,621,20,644,627.ttf
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.633,645,627,621,20,644,627.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.633,6D2.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.633,6D2.ttf
index 5683d04..953fa21 100644
--- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.633,6D2.ttf
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.633,6D2.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.63A,64A,631.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.63A,64A,631.ttf
index e19feda..412f534 100644
--- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.63A,64A,631.ttf
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.63A,64A,631.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.retain-all-codepoint.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.all.ttf
similarity index 99%
rename from test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.retain-all-codepoint.ttf
rename to test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.all.ttf
index ea153c9..c6c17ff 100644
--- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644,623,62D,644,627,645,2E.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644,623,62D,644,627,645,2E.ttf
index 4df2620..d71a950 100644
--- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644,623,62D,644,627,645,2E.ttf
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644,623,62D,644,627,645,2E.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644,62D,628.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644,62D,628.ttf
index fb9746e..f278d34 100644
--- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644,62D,628.ttf
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644,62D,628.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644.ttf
index 1ef5e8d..ab83c05 100644
--- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644.ttf
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.633,645,627,621,20,644,627.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.633,645,627,621,20,644,627.ttf
index 5e2dee1..180c881 100644
--- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.633,645,627,621,20,644,627.ttf
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.633,645,627,621,20,644,627.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.633,6D2.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.633,6D2.ttf
index 81319fd..89a186a 100644
--- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.633,6D2.ttf
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.633,6D2.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.63A,64A,631.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.63A,64A,631.ttf
index b9aa70b..cba2f55 100644
--- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.63A,64A,631.ttf
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.63A,64A,631.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.all.ttf
similarity index 99%
rename from test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.retain-all-codepoint.ttf
rename to test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.all.ttf
index 4458d5f..2b453f0 100644
--- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.tinos/Tinos-Italic.default.retain-all-codepoint.ttf b/test/subset/data/expected/layout.tinos/Tinos-Italic.default.all.ttf
similarity index 100%
rename from test/subset/data/expected/layout.tinos/Tinos-Italic.default.retain-all-codepoint.ttf
rename to test/subset/data/expected/layout.tinos/Tinos-Italic.default.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.tinos/Tinos-Italic.glyph-names.retain-all-codepoint.ttf b/test/subset/data/expected/layout.tinos/Tinos-Italic.glyph-names.all.ttf
similarity index 100%
rename from test/subset/data/expected/layout.tinos/Tinos-Italic.glyph-names.retain-all-codepoint.ttf
rename to test/subset/data/expected/layout.tinos/Tinos-Italic.glyph-names.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.tinos/Tinos-Italic.default.retain-all-codepoint.ttf b/test/subset/data/expected/layout.tinos/Tinos-Italic.notdef-outline.all.ttf
similarity index 100%
copy from test/subset/data/expected/layout.tinos/Tinos-Italic.default.retain-all-codepoint.ttf
copy to test/subset/data/expected/layout.tinos/Tinos-Italic.notdef-outline.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.tinos/Tinos-Italic.notdef-outline.retain-all-codepoint.ttf b/test/subset/data/expected/layout.tinos/Tinos-Italic.notdef-outline.retain-all-codepoint.ttf
deleted file mode 100644
index b1c5769..0000000
--- a/test/subset/data/expected/layout.tinos/Tinos-Italic.notdef-outline.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.tinos/Tinos-Italic.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/layout.tinos/Tinos-Italic.retain-gids.all.ttf
similarity index 100%
rename from test/subset/data/expected/layout.tinos/Tinos-Italic.retain-gids.retain-all-codepoint.ttf
rename to test/subset/data/expected/layout.tinos/Tinos-Italic.retain-gids.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.default.392,3a7,3b2,3c7.ttf b/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.default.392,3a7,3b2,3c7.ttf
index 3fb42c6..b9045f1 100644
--- a/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.default.392,3a7,3b2,3c7.ttf
+++ b/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.default.392,3a7,3b2,3c7.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.default.retain-all-codepoint.ttf b/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.default.all.ttf
similarity index 98%
rename from test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.default.retain-all-codepoint.ttf
rename to test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.default.all.ttf
index 8bf70ed..067526c 100644
--- a/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.default.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.layout-test.392,3a7,3b2,3c7.ttf b/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.layout-test.392,3a7,3b2,3c7.ttf
index a0b6145..5de3483 100644
--- a/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.layout-test.392,3a7,3b2,3c7.ttf
+++ b/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.layout-test.392,3a7,3b2,3c7.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.layout-test.retain-all-codepoint.ttf b/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.layout-test.all.ttf
similarity index 98%
rename from test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.layout-test.retain-all-codepoint.ttf
rename to test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.layout-test.all.ttf
index 770b359..17d2eb8 100644
--- a/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.layout-test.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.layout-test.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.retain-gids.392,3a7,3b2,3c7.ttf b/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.retain-gids.392,3a7,3b2,3c7.ttf
index 012bb16..6201d22 100644
--- a/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.retain-gids.392,3a7,3b2,3c7.ttf
+++ b/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.retain-gids.392,3a7,3b2,3c7.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.retain-gids.all.ttf
similarity index 98%
rename from test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.retain-gids.retain-all-codepoint.ttf
rename to test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.retain-gids.all.ttf
index c7e0040..55440c4 100644
--- a/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.retain-gids.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.retain-gids.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.41,42,43.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.41,42,43.ttf
index 908d200..6162c01 100644
--- a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.41,42,43.ttf
+++ b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.41,42,43.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.41,43.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.41,43.ttf
index 483e409..5e4324d 100644
--- a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.41,43.ttf
+++ b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.41,43.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.41.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.41.ttf
index f3685e4..6e45f51 100644
--- a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.41.ttf
+++ b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.41.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.43.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.43.ttf
index b33c28f..75cb12d 100644
--- a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.43.ttf
+++ b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.43.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.CA,CB.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.CA,CB.ttf
index c6098b2..d19640c 100644
--- a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.CA,CB.ttf
+++ b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.CA,CB.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.41,42,43.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.41,42,43.ttf
index fb0bbad..34ac349 100644
--- a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.41,42,43.ttf
+++ b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.41,42,43.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.41,43.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.41,43.ttf
index 6d30e6d..e0c72e9 100644
--- a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.41,43.ttf
+++ b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.41,43.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.41.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.41.ttf
index 24bfcaf..e7ff1f6 100644
--- a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.41.ttf
+++ b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.41.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.43.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.43.ttf
index 37b6cee..4c3ab7b 100644
--- a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.43.ttf
+++ b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.43.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.CA,CB.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.CA,CB.ttf
index 0445fd8..43842b8 100644
--- a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.CA,CB.ttf
+++ b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.CA,CB.ttf
Binary files differ
diff --git a/test/subset/data/expected/math/STIXTwoMath-Regular.default.retain-all-codepoint.ttf b/test/subset/data/expected/math/STIXTwoMath-Regular.default.all.ttf
similarity index 100%
rename from test/subset/data/expected/math/STIXTwoMath-Regular.default.retain-all-codepoint.ttf
rename to test/subset/data/expected/math/STIXTwoMath-Regular.default.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/math/STIXTwoMath-Regular.glyph-names.retain-all-codepoint.ttf b/test/subset/data/expected/math/STIXTwoMath-Regular.glyph-names.all.ttf
similarity index 100%
rename from test/subset/data/expected/math/STIXTwoMath-Regular.glyph-names.retain-all-codepoint.ttf
rename to test/subset/data/expected/math/STIXTwoMath-Regular.glyph-names.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/math/STIXTwoMath-Regular.notdef-outline.retain-all-codepoint.ttf b/test/subset/data/expected/math/STIXTwoMath-Regular.notdef-outline.all.ttf
similarity index 100%
rename from test/subset/data/expected/math/STIXTwoMath-Regular.notdef-outline.retain-all-codepoint.ttf
rename to test/subset/data/expected/math/STIXTwoMath-Regular.notdef-outline.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/math/STIXTwoMath-Regular.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/math/STIXTwoMath-Regular.retain-gids.all.ttf
similarity index 100%
rename from test/subset/data/expected/math/STIXTwoMath-Regular.retain-gids.retain-all-codepoint.ttf
rename to test/subset/data/expected/math/STIXTwoMath-Regular.retain-gids.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/math_coverage_offset/Caudex-Regular.default.retain-all-codepoint.ttf b/test/subset/data/expected/math_coverage_offset/Caudex-Regular.default.all.ttf
similarity index 100%
rename from test/subset/data/expected/math_coverage_offset/Caudex-Regular.default.retain-all-codepoint.ttf
rename to test/subset/data/expected/math_coverage_offset/Caudex-Regular.default.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/math_coverage_offset/Caudex-Regular.glyph-names.retain-all-codepoint.ttf b/test/subset/data/expected/math_coverage_offset/Caudex-Regular.glyph-names.all.ttf
similarity index 100%
rename from test/subset/data/expected/math_coverage_offset/Caudex-Regular.glyph-names.retain-all-codepoint.ttf
rename to test/subset/data/expected/math_coverage_offset/Caudex-Regular.glyph-names.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/math_coverage_offset/Caudex-Regular.default.retain-all-codepoint.ttf b/test/subset/data/expected/math_coverage_offset/Caudex-Regular.keep-all-layout-features.all.ttf
similarity index 100%
copy from test/subset/data/expected/math_coverage_offset/Caudex-Regular.default.retain-all-codepoint.ttf
copy to test/subset/data/expected/math_coverage_offset/Caudex-Regular.keep-all-layout-features.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/math_coverage_offset/Caudex-Regular.keep-all-layout-features.retain-all-codepoint.ttf b/test/subset/data/expected/math_coverage_offset/Caudex-Regular.keep-all-layout-features.retain-all-codepoint.ttf
deleted file mode 100644
index 0df9dca..0000000
--- a/test/subset/data/expected/math_coverage_offset/Caudex-Regular.keep-all-layout-features.retain-all-codepoint.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/math_coverage_offset/Caudex-Regular.notdef-outline.retain-all-codepoint.ttf b/test/subset/data/expected/math_coverage_offset/Caudex-Regular.notdef-outline.all.ttf
similarity index 100%
rename from test/subset/data/expected/math_coverage_offset/Caudex-Regular.notdef-outline.retain-all-codepoint.ttf
rename to test/subset/data/expected/math_coverage_offset/Caudex-Regular.notdef-outline.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/math_coverage_offset/Caudex-Regular.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/math_coverage_offset/Caudex-Regular.retain-gids.all.ttf
similarity index 100%
rename from test/subset/data/expected/math_coverage_offset/Caudex-Regular.retain-gids.retain-all-codepoint.ttf
rename to test/subset/data/expected/math_coverage_offset/Caudex-Regular.retain-gids.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/mvar_full_instance/NotoSans-VF.abc.no-layout.retain-all-codepoint.wght=150,wdth=80,CTGR=0.ttf b/test/subset/data/expected/mvar_full_instance/NotoSans-VF.abc.no-layout.all.wght=150,wdth=80,CTGR=0.ttf
similarity index 86%
rename from test/subset/data/expected/mvar_full_instance/NotoSans-VF.abc.no-layout.retain-all-codepoint.wght=150,wdth=80,CTGR=0.ttf
rename to test/subset/data/expected/mvar_full_instance/NotoSans-VF.abc.no-layout.all.wght=150,wdth=80,CTGR=0.ttf
index 5a46c64..b86ed16 100644
--- a/test/subset/data/expected/mvar_full_instance/NotoSans-VF.abc.no-layout.retain-all-codepoint.wght=150,wdth=80,CTGR=0.ttf
+++ b/test/subset/data/expected/mvar_full_instance/NotoSans-VF.abc.no-layout.all.wght=150,wdth=80,CTGR=0.ttf
Binary files differ
diff --git a/test/subset/data/expected/mvar_full_instance/NotoSans-VF.abc.no-layout.retain-all-codepoint.wght=300,wdth=90,CTGR=0.ttf b/test/subset/data/expected/mvar_full_instance/NotoSans-VF.abc.no-layout.all.wght=300,wdth=90,CTGR=0.ttf
similarity index 86%
rename from test/subset/data/expected/mvar_full_instance/NotoSans-VF.abc.no-layout.retain-all-codepoint.wght=300,wdth=90,CTGR=0.ttf
rename to test/subset/data/expected/mvar_full_instance/NotoSans-VF.abc.no-layout.all.wght=300,wdth=90,CTGR=0.ttf
index dad3489..bcc6fec 100644
--- a/test/subset/data/expected/mvar_full_instance/NotoSans-VF.abc.no-layout.retain-all-codepoint.wght=300,wdth=90,CTGR=0.ttf
+++ b/test/subset/data/expected/mvar_full_instance/NotoSans-VF.abc.no-layout.all.wght=300,wdth=90,CTGR=0.ttf
Binary files differ
diff --git a/test/subset/data/expected/mvar_partial_instance/NotoSans-VF.abc.default.all.wght=200-600,wdth=80-90,CTGR=20-60.iup_optimize.ttf b/test/subset/data/expected/mvar_partial_instance/NotoSans-VF.abc.default.all.wght=200-600,wdth=80-90,CTGR=20-60.iup_optimize.ttf
new file mode 100644
index 0000000..757b2dd
--- /dev/null
+++ b/test/subset/data/expected/mvar_partial_instance/NotoSans-VF.abc.default.all.wght=200-600,wdth=80-90,CTGR=20-60.iup_optimize.ttf
Binary files differ
diff --git a/test/subset/data/expected/mvar_partial_instance/NotoSans-VF.abc.no-tables-with-item-variations.retain-all-codepoint.wght=200-600,wdth=80-90,CTGR=20-60.ttf b/test/subset/data/expected/mvar_partial_instance/NotoSans-VF.abc.default.all.wght=200-600,wdth=80-90,CTGR=20-60.ttf
similarity index 82%
rename from test/subset/data/expected/mvar_partial_instance/NotoSans-VF.abc.no-tables-with-item-variations.retain-all-codepoint.wght=200-600,wdth=80-90,CTGR=20-60.ttf
rename to test/subset/data/expected/mvar_partial_instance/NotoSans-VF.abc.default.all.wght=200-600,wdth=80-90,CTGR=20-60.ttf
index 78f0d69..80f18f9 100644
--- a/test/subset/data/expected/mvar_partial_instance/NotoSans-VF.abc.no-tables-with-item-variations.retain-all-codepoint.wght=200-600,wdth=80-90,CTGR=20-60.ttf
+++ b/test/subset/data/expected/mvar_partial_instance/NotoSans-VF.abc.default.all.wght=200-600,wdth=80-90,CTGR=20-60.ttf
Binary files differ
diff --git a/test/subset/data/expected/mvar_partial_instance/NotoSans-VF.abc.default.all.wght=300-600.iup_optimize.ttf b/test/subset/data/expected/mvar_partial_instance/NotoSans-VF.abc.default.all.wght=300-600.iup_optimize.ttf
new file mode 100644
index 0000000..a832005
--- /dev/null
+++ b/test/subset/data/expected/mvar_partial_instance/NotoSans-VF.abc.default.all.wght=300-600.iup_optimize.ttf
Binary files differ
diff --git a/test/subset/data/expected/mvar_partial_instance/NotoSans-VF.abc.no-tables-with-item-variations.retain-all-codepoint.wght=300-600.ttf b/test/subset/data/expected/mvar_partial_instance/NotoSans-VF.abc.default.all.wght=300-600.ttf
similarity index 86%
rename from test/subset/data/expected/mvar_partial_instance/NotoSans-VF.abc.no-tables-with-item-variations.retain-all-codepoint.wght=300-600.ttf
rename to test/subset/data/expected/mvar_partial_instance/NotoSans-VF.abc.default.all.wght=300-600.ttf
index 8c5e3df..d46da23 100644
--- a/test/subset/data/expected/mvar_partial_instance/NotoSans-VF.abc.no-tables-with-item-variations.retain-all-codepoint.wght=300-600.ttf
+++ b/test/subset/data/expected/mvar_partial_instance/NotoSans-VF.abc.default.all.wght=300-600.ttf
Binary files differ
diff --git a/test/subset/data/expected/mvar_partial_instance/NotoSans-VF.abc.default.all.wght=500-800.iup_optimize.ttf b/test/subset/data/expected/mvar_partial_instance/NotoSans-VF.abc.default.all.wght=500-800.iup_optimize.ttf
new file mode 100644
index 0000000..258c56a
--- /dev/null
+++ b/test/subset/data/expected/mvar_partial_instance/NotoSans-VF.abc.default.all.wght=500-800.iup_optimize.ttf
Binary files differ
diff --git a/test/subset/data/expected/mvar_partial_instance/NotoSans-VF.abc.default.all.wght=500-800.ttf b/test/subset/data/expected/mvar_partial_instance/NotoSans-VF.abc.default.all.wght=500-800.ttf
new file mode 100644
index 0000000..c65f124
--- /dev/null
+++ b/test/subset/data/expected/mvar_partial_instance/NotoSans-VF.abc.default.all.wght=500-800.ttf
Binary files differ
diff --git a/test/subset/data/expected/mvar_partial_instance/NotoSans-VF.abc.no-tables-with-item-variations.retain-all-codepoint.wght=500-800.ttf b/test/subset/data/expected/mvar_partial_instance/NotoSans-VF.abc.no-tables-with-item-variations.retain-all-codepoint.wght=500-800.ttf
deleted file mode 100644
index fc18d57..0000000
--- a/test/subset/data/expected/mvar_partial_instance/NotoSans-VF.abc.no-tables-with-item-variations.retain-all-codepoint.wght=500-800.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/no_layout_closure/Roboto-Regular.no-layout-closure-gids.no-unicodes.ttf b/test/subset/data/expected/no_layout_closure/Roboto-Regular.no-layout-closure-gids.no-unicodes.ttf
index 73458aa..f5b97f4 100644
--- a/test/subset/data/expected/no_layout_closure/Roboto-Regular.no-layout-closure-gids.no-unicodes.ttf
+++ b/test/subset/data/expected/no_layout_closure/Roboto-Regular.no-layout-closure-gids.no-unicodes.ttf
Binary files differ
diff --git a/test/subset/data/expected/no_layout_closure/Roboto-Regular.no-layout-closure-gids2.no-unicodes.ttf b/test/subset/data/expected/no_layout_closure/Roboto-Regular.no-layout-closure-gids2.no-unicodes.ttf
index 592a5f3..e490b23 100644
--- a/test/subset/data/expected/no_layout_closure/Roboto-Regular.no-layout-closure-gids2.no-unicodes.ttf
+++ b/test/subset/data/expected/no_layout_closure/Roboto-Regular.no-layout-closure-gids2.no-unicodes.ttf
Binary files differ
diff --git a/test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.retain-all-codepoint.wght=400,wdth=100.0.ttf b/test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.all.wght=400,wdth=100.0.ttf
similarity index 88%
rename from test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.retain-all-codepoint.wght=400,wdth=100.0.ttf
rename to test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.all.wght=400,wdth=100.0.ttf
index adceacd..42535d9 100644
--- a/test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.retain-all-codepoint.wght=400,wdth=100.0.ttf
+++ b/test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.all.wght=400,wdth=100.0.ttf
Binary files differ
diff --git a/test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.retain-all-codepoint.wght=400,wdth=100.0.ttf b/test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.all.wght=drop,wdth=100.ttf
similarity index 88%
copy from test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.retain-all-codepoint.wght=400,wdth=100.0.ttf
copy to test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.all.wght=drop,wdth=100.ttf
index adceacd..42535d9 100644
--- a/test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.retain-all-codepoint.wght=400,wdth=100.0.ttf
+++ b/test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.all.wght=drop,wdth=100.ttf
Binary files differ
diff --git a/test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.retain-all-codepoint.wght=drop,wdth=100.ttf b/test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.retain-all-codepoint.wght=drop,wdth=100.ttf
deleted file mode 100644
index adceacd..0000000
--- a/test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.retain-all-codepoint.wght=drop,wdth=100.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.default.retain-all-codepoint.ttf b/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.default.all.ttf
similarity index 100%
rename from test/subset/data/expected/post/SreeKrushnadevaraya-Regular.default.retain-all-codepoint.ttf
rename to test/subset/data/expected/post/SreeKrushnadevaraya-Regular.default.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.glyph-names.retain-all-codepoint.ttf b/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.glyph-names.all.ttf
similarity index 100%
rename from test/subset/data/expected/post/SreeKrushnadevaraya-Regular.glyph-names.retain-all-codepoint.ttf
rename to test/subset/data/expected/post/SreeKrushnadevaraya-Regular.glyph-names.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.notdef-outline.retain-all-codepoint.ttf b/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.notdef-outline.all.ttf
similarity index 100%
rename from test/subset/data/expected/post/SreeKrushnadevaraya-Regular.notdef-outline.retain-all-codepoint.ttf
rename to test/subset/data/expected/post/SreeKrushnadevaraya-Regular.notdef-outline.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.retain-gids.all.ttf
similarity index 100%
rename from test/subset/data/expected/post/SreeKrushnadevaraya-Regular.retain-gids.retain-all-codepoint.ttf
rename to test/subset/data/expected/post/SreeKrushnadevaraya-Regular.retain-gids.all.ttf
Binary files differ
diff --git a/test/subset/data/expected/post_apply_mvar_delta/Recursive-ABC.no-layout.retain-all-codepoint.wght=400,CASL=0,CRSV=0,MONO=0,slnt=0.ttf b/test/subset/data/expected/post_apply_mvar_delta/Recursive-ABC.no-layout.all.wght=400,CASL=0,CRSV=0,MONO=0,slnt=0.ttf
similarity index 93%
rename from test/subset/data/expected/post_apply_mvar_delta/Recursive-ABC.no-layout.retain-all-codepoint.wght=400,CASL=0,CRSV=0,MONO=0,slnt=0.ttf
rename to test/subset/data/expected/post_apply_mvar_delta/Recursive-ABC.no-layout.all.wght=400,CASL=0,CRSV=0,MONO=0,slnt=0.ttf
index 08a3081..391ce7c 100644
--- a/test/subset/data/expected/post_apply_mvar_delta/Recursive-ABC.no-layout.retain-all-codepoint.wght=400,CASL=0,CRSV=0,MONO=0,slnt=0.ttf
+++ b/test/subset/data/expected/post_apply_mvar_delta/Recursive-ABC.no-layout.all.wght=400,CASL=0,CRSV=0,MONO=0,slnt=0.ttf
Binary files differ
diff --git a/test/subset/data/expected/post_apply_mvar_delta/Recursive-ABC.no-layout.all.wght=500,CASL=0,CRSV=0,MONO=0,slnt=0.ttf b/test/subset/data/expected/post_apply_mvar_delta/Recursive-ABC.no-layout.all.wght=500,CASL=0,CRSV=0,MONO=0,slnt=0.ttf
new file mode 100644
index 0000000..3e21d99
--- /dev/null
+++ b/test/subset/data/expected/post_apply_mvar_delta/Recursive-ABC.no-layout.all.wght=500,CASL=0,CRSV=0,MONO=0,slnt=0.ttf
Binary files differ
diff --git a/test/subset/data/expected/preprocess/Roboto-Regular.gids.61,62,63,30D9.ttf b/test/subset/data/expected/preprocess/Roboto-Regular.gids.61,62,63,30D9.ttf
index 5f8bff0..4852281 100644
--- a/test/subset/data/expected/preprocess/Roboto-Regular.gids.61,62,63,30D9.ttf
+++ b/test/subset/data/expected/preprocess/Roboto-Regular.gids.61,62,63,30D9.ttf
Binary files differ
diff --git a/test/subset/data/expected/subset_base/SourceSansPro-Regular.retain-base-table-filter-scripts.61,62,63.otf b/test/subset/data/expected/subset_base/SourceSansPro-Regular.retain-base-table-filter-scripts.61,62,63.otf
new file mode 100644
index 0000000..8fff795
--- /dev/null
+++ b/test/subset/data/expected/subset_base/SourceSansPro-Regular.retain-base-table-filter-scripts.61,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/subset_base/SourceSansPro-Regular.retain-base-table.61,62,63.otf b/test/subset/data/expected/subset_base/SourceSansPro-Regular.retain-base-table.61,62,63.otf
new file mode 100644
index 0000000..5982487
--- /dev/null
+++ b/test/subset/data/expected/subset_base/SourceSansPro-Regular.retain-base-table.61,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/sync_vmetrics/playwrite_mm.subset.default.all.SPED=25,YEXT=520,wght=100-400,slnt=18.iup_optimize.ttf b/test/subset/data/expected/sync_vmetrics/playwrite_mm.subset.default.all.SPED=25,YEXT=520,wght=100-400,slnt=18.iup_optimize.ttf
new file mode 100644
index 0000000..1bf7b04
--- /dev/null
+++ b/test/subset/data/expected/sync_vmetrics/playwrite_mm.subset.default.all.SPED=25,YEXT=520,wght=100-400,slnt=18.iup_optimize.ttf
Binary files differ
diff --git a/test/subset/data/expected/sync_vmetrics/playwrite_mm.subset.default.all.SPED=25,YEXT=520,wght=100-400,slnt=18.ttf b/test/subset/data/expected/sync_vmetrics/playwrite_mm.subset.default.all.SPED=25,YEXT=520,wght=100-400,slnt=18.ttf
new file mode 100644
index 0000000..1bf7b04
--- /dev/null
+++ b/test/subset/data/expected/sync_vmetrics/playwrite_mm.subset.default.all.SPED=25,YEXT=520,wght=100-400,slnt=18.ttf
Binary files differ
diff --git a/test/subset/data/expected/update_def_wght/SourceSerifVariable-Roman.no-tables-with-item-variations.retain-all-codepoint.wght=300-600.ttf b/test/subset/data/expected/update_def_wght/SourceSerifVariable-Roman.default.all.wght=300-600.iup_optimize.ttf
similarity index 89%
copy from test/subset/data/expected/update_def_wght/SourceSerifVariable-Roman.no-tables-with-item-variations.retain-all-codepoint.wght=300-600.ttf
copy to test/subset/data/expected/update_def_wght/SourceSerifVariable-Roman.default.all.wght=300-600.iup_optimize.ttf
index 2c8f3e7..b20d328 100644
--- a/test/subset/data/expected/update_def_wght/SourceSerifVariable-Roman.no-tables-with-item-variations.retain-all-codepoint.wght=300-600.ttf
+++ b/test/subset/data/expected/update_def_wght/SourceSerifVariable-Roman.default.all.wght=300-600.iup_optimize.ttf
Binary files differ
diff --git a/test/subset/data/expected/update_def_wght/SourceSerifVariable-Roman.no-tables-with-item-variations.retain-all-codepoint.wght=300-600.ttf b/test/subset/data/expected/update_def_wght/SourceSerifVariable-Roman.default.all.wght=300-600.ttf
similarity index 99%
rename from test/subset/data/expected/update_def_wght/SourceSerifVariable-Roman.no-tables-with-item-variations.retain-all-codepoint.wght=300-600.ttf
rename to test/subset/data/expected/update_def_wght/SourceSerifVariable-Roman.default.all.wght=300-600.ttf
index 2c8f3e7..7819341 100644
--- a/test/subset/data/expected/update_def_wght/SourceSerifVariable-Roman.no-tables-with-item-variations.retain-all-codepoint.wght=300-600.ttf
+++ b/test/subset/data/expected/update_def_wght/SourceSerifVariable-Roman.default.all.wght=300-600.ttf
Binary files differ
diff --git a/test/subset/data/expected/update_def_wght/SourceSerifVariable-Roman.no-tables-with-item-variations.retain-all-codepoint.wght=500-800.ttf b/test/subset/data/expected/update_def_wght/SourceSerifVariable-Roman.default.all.wght=500-800.iup_optimize.ttf
similarity index 93%
copy from test/subset/data/expected/update_def_wght/SourceSerifVariable-Roman.no-tables-with-item-variations.retain-all-codepoint.wght=500-800.ttf
copy to test/subset/data/expected/update_def_wght/SourceSerifVariable-Roman.default.all.wght=500-800.iup_optimize.ttf
index f50af52..edbda6a 100644
--- a/test/subset/data/expected/update_def_wght/SourceSerifVariable-Roman.no-tables-with-item-variations.retain-all-codepoint.wght=500-800.ttf
+++ b/test/subset/data/expected/update_def_wght/SourceSerifVariable-Roman.default.all.wght=500-800.iup_optimize.ttf
Binary files differ
diff --git a/test/subset/data/expected/update_def_wght/SourceSerifVariable-Roman.no-tables-with-item-variations.retain-all-codepoint.wght=500-800.ttf b/test/subset/data/expected/update_def_wght/SourceSerifVariable-Roman.default.all.wght=500-800.ttf
similarity index 99%
rename from test/subset/data/expected/update_def_wght/SourceSerifVariable-Roman.no-tables-with-item-variations.retain-all-codepoint.wght=500-800.ttf
rename to test/subset/data/expected/update_def_wght/SourceSerifVariable-Roman.default.all.wght=500-800.ttf
index f50af52..c8e72dd 100644
--- a/test/subset/data/expected/update_def_wght/SourceSerifVariable-Roman.no-tables-with-item-variations.retain-all-codepoint.wght=500-800.ttf
+++ b/test/subset/data/expected/update_def_wght/SourceSerifVariable-Roman.default.all.wght=500-800.ttf
Binary files differ
diff --git a/test/subset/data/expected/value_format_partial_instance/NotoSansOriya-valueformat-subset.default.all.wght=400.iup_optimize.ttf b/test/subset/data/expected/value_format_partial_instance/NotoSansOriya-valueformat-subset.default.all.wght=400.iup_optimize.ttf
new file mode 100644
index 0000000..b4a6ab7
--- /dev/null
+++ b/test/subset/data/expected/value_format_partial_instance/NotoSansOriya-valueformat-subset.default.all.wght=400.iup_optimize.ttf
Binary files differ
diff --git a/test/subset/data/expected/value_format_partial_instance/NotoSansOriya-valueformat-subset.default.all.wght=400.ttf b/test/subset/data/expected/value_format_partial_instance/NotoSansOriya-valueformat-subset.default.all.wght=400.ttf
new file mode 100644
index 0000000..b4a6ab7
--- /dev/null
+++ b/test/subset/data/expected/value_format_partial_instance/NotoSansOriya-valueformat-subset.default.all.wght=400.ttf
Binary files differ
diff --git a/test/subset/data/expected/value_format_partial_instance/NotoSansOriya-valueformat-subset.drop-hints.all.wght=400.iup_optimize.ttf b/test/subset/data/expected/value_format_partial_instance/NotoSansOriya-valueformat-subset.drop-hints.all.wght=400.iup_optimize.ttf
new file mode 100644
index 0000000..0e1c801
--- /dev/null
+++ b/test/subset/data/expected/value_format_partial_instance/NotoSansOriya-valueformat-subset.drop-hints.all.wght=400.iup_optimize.ttf
Binary files differ
diff --git a/test/subset/data/expected/value_format_partial_instance/NotoSansOriya-valueformat-subset.drop-hints.all.wght=400.ttf b/test/subset/data/expected/value_format_partial_instance/NotoSansOriya-valueformat-subset.drop-hints.all.wght=400.ttf
new file mode 100644
index 0000000..0e1c801
--- /dev/null
+++ b/test/subset/data/expected/value_format_partial_instance/NotoSansOriya-valueformat-subset.drop-hints.all.wght=400.ttf
Binary files differ
diff --git a/test/subset/data/fonts/AnekBangla-latin-subset.ttf b/test/subset/data/fonts/AnekBangla-latin-subset.ttf
new file mode 100644
index 0000000..e940516
--- /dev/null
+++ b/test/subset/data/fonts/AnekBangla-latin-subset.ttf
Binary files differ
diff --git a/test/subset/data/fonts/AnekBangla-question-subset.ttf b/test/subset/data/fonts/AnekBangla-question-subset.ttf
new file mode 100644
index 0000000..44ff098
--- /dev/null
+++ b/test/subset/data/fonts/AnekBangla-question-subset.ttf
Binary files differ
diff --git a/test/subset/data/fonts/AnekBangla-subset.ttf b/test/subset/data/fonts/AnekBangla-subset.ttf
new file mode 100644
index 0000000..3595d25
--- /dev/null
+++ b/test/subset/data/fonts/AnekBangla-subset.ttf
Binary files differ
diff --git a/test/subset/data/fonts/KalniaGlaze.ttf b/test/subset/data/fonts/KalniaGlaze.ttf
new file mode 100644
index 0000000..52036fa
--- /dev/null
+++ b/test/subset/data/fonts/KalniaGlaze.ttf
Binary files differ
diff --git a/test/subset/data/fonts/Muli-ABC.ttf b/test/subset/data/fonts/Muli-ABC.ttf
index 60e6520..0e9522d 100644
--- a/test/subset/data/fonts/Muli-ABC.ttf
+++ b/test/subset/data/fonts/Muli-ABC.ttf
Binary files differ
diff --git a/test/subset/data/fonts/NotoSansOriya-subset.ttf b/test/subset/data/fonts/NotoSansOriya-subset.ttf
new file mode 100644
index 0000000..9357b99
--- /dev/null
+++ b/test/subset/data/fonts/NotoSansOriya-subset.ttf
Binary files differ
diff --git a/test/subset/data/fonts/NotoSansOriya-valueformat-subset.ttf b/test/subset/data/fonts/NotoSansOriya-valueformat-subset.ttf
new file mode 100644
index 0000000..ffdcd46
--- /dev/null
+++ b/test/subset/data/fonts/NotoSansOriya-valueformat-subset.ttf
Binary files differ
diff --git a/test/subset/data/fonts/NotoSerifHK-subset.ttf b/test/subset/data/fonts/NotoSerifHK-subset.ttf
new file mode 100644
index 0000000..0647297
--- /dev/null
+++ b/test/subset/data/fonts/NotoSerifHK-subset.ttf
Binary files differ
diff --git a/test/subset/data/fonts/Roboto-Variable.ABC.ttf b/test/subset/data/fonts/Roboto-Variable.ABC.ttf
index 6cf001f..a70db42 100644
--- a/test/subset/data/fonts/Roboto-Variable.ABC.ttf
+++ b/test/subset/data/fonts/Roboto-Variable.ABC.ttf
Binary files differ
diff --git a/test/subset/data/fonts/RobotoFlex-Variable.ABC.ttf b/test/subset/data/fonts/RobotoFlex-Variable.ABC.ttf
new file mode 100644
index 0000000..d8571ad
--- /dev/null
+++ b/test/subset/data/fonts/RobotoFlex-Variable.ABC.ttf
Binary files differ
diff --git a/test/subset/data/fonts/playwrite_mm.subset.ttf b/test/subset/data/fonts/playwrite_mm.subset.ttf
new file mode 100644
index 0000000..e939c85
--- /dev/null
+++ b/test/subset/data/fonts/playwrite_mm.subset.ttf
Binary files differ
diff --git a/test/subset/data/profiles/iftb_requirements.txt b/test/subset/data/profiles/iftb_requirements.txt
new file mode 100644
index 0000000..3f8692e
--- /dev/null
+++ b/test/subset/data/profiles/iftb_requirements.txt
@@ -0,0 +1 @@
+--iftb-requirements
diff --git a/test/subset/data/profiles/no-tables-with-item-variations.txt b/test/subset/data/profiles/no-tables-with-item-variations.txt
deleted file mode 100644
index d61fb71..0000000
--- a/test/subset/data/profiles/no-tables-with-item-variations.txt
+++ /dev/null
@@ -1 +0,0 @@
---drop-tables+=COLR
diff --git a/test/subset/data/profiles/retain-base-table-filter-scripts.txt b/test/subset/data/profiles/retain-base-table-filter-scripts.txt
new file mode 100644
index 0000000..05b2626
--- /dev/null
+++ b/test/subset/data/profiles/retain-base-table-filter-scripts.txt
@@ -0,0 +1,2 @@
+--drop-tables-=BASE
+--layout-scripts=grek,cyrl
diff --git a/test/subset/data/profiles/retain-base-table.txt b/test/subset/data/profiles/retain-base-table.txt
new file mode 100644
index 0000000..92cecd4
--- /dev/null
+++ b/test/subset/data/profiles/retain-base-table.txt
@@ -0,0 +1 @@
+--drop-tables-=BASE
diff --git a/test/subset/data/tests/colrv1_copy_varstore.tests b/test/subset/data/tests/colrv1_subset_varstore.tests
similarity index 83%
rename from test/subset/data/tests/colrv1_copy_varstore.tests
rename to test/subset/data/tests/colrv1_subset_varstore.tests
index c698ece..70ea989 100644
--- a/test/subset/data/tests/colrv1_copy_varstore.tests
+++ b/test/subset/data/tests/colrv1_subset_varstore.tests
@@ -11,3 +11,6 @@
 A
 AB
 *
+
+OPTIONS:
+no_fonttools
diff --git a/test/subset/data/tests/empty_region_vardata.tests b/test/subset/data/tests/empty_region_vardata.tests
new file mode 100644
index 0000000..a4368d5
--- /dev/null
+++ b/test/subset/data/tests/empty_region_vardata.tests
@@ -0,0 +1,20 @@
+FONTS:
+RobotoFlex-Variable.ABC.ttf
+
+PROFILES:
+default.txt
+
+SUBSETS:
+*
+
+INSTANCES:
+wght=400,wdth=100,opsz=14
+wght=200:300,opsz=14
+
+IUP_OPTIONS:
+Yes
+No
+
+OPTIONS:
+no_fonttools
+# TODO: re-enable fonttools once rounding issues are fixed (https://github.com/harfbuzz/harfbuzz/issues/4642)
diff --git a/test/subset/data/tests/feature_variation_instance_collect_lookups.tests b/test/subset/data/tests/feature_variation_instance_collect_lookups.tests
new file mode 100644
index 0000000..b8a74d8
--- /dev/null
+++ b/test/subset/data/tests/feature_variation_instance_collect_lookups.tests
@@ -0,0 +1,15 @@
+FONTS:
+AnekBangla-question-subset.ttf
+
+PROFILES:
+default.txt
+
+SUBSETS:
+*
+
+INSTANCES:
+wdth=112.5
+
+IUP_OPTIONS:
+Yes
+No
diff --git a/test/subset/data/tests/feature_variations_partial_instance.tests b/test/subset/data/tests/feature_variations_partial_instance.tests
new file mode 100644
index 0000000..0f98e7a
--- /dev/null
+++ b/test/subset/data/tests/feature_variations_partial_instance.tests
@@ -0,0 +1,16 @@
+FONTS:
+NotoSansOriya-subset.ttf
+
+PROFILES:
+default.txt
+keep-all-layout-features.txt
+
+SUBSETS:
+*
+
+INSTANCES:
+wdth=75
+
+IUP_OPTIONS:
+Yes
+No
diff --git a/test/subset/data/tests/gdef_partial_instance.tests b/test/subset/data/tests/gdef_partial_instance.tests
new file mode 100644
index 0000000..17a3a4e
--- /dev/null
+++ b/test/subset/data/tests/gdef_partial_instance.tests
@@ -0,0 +1,15 @@
+FONTS:
+AnekBangla-subset.ttf
+
+PROFILES:
+default.txt
+
+SUBSETS:
+*
+
+INSTANCES:
+wght=300
+
+IUP_OPTIONS:
+Yes
+No
diff --git a/test/subset/data/tests/glyf_partial_instancing.tests b/test/subset/data/tests/glyf_partial_instancing.tests
index c0cb129..ebb4566 100644
--- a/test/subset/data/tests/glyf_partial_instancing.tests
+++ b/test/subset/data/tests/glyf_partial_instancing.tests
@@ -3,7 +3,7 @@
 Roboto-Variable.composite.ttf
 
 PROFILES:
-no-tables-with-item-variations.txt
+default.txt
 
 SUBSETS:
 *
@@ -11,3 +11,7 @@
 INSTANCES:
 wght=300:600,wdth=85
 wght=200:300:500,wdth=80:90
+
+IUP_OPTIONS:
+Yes
+No
diff --git a/test/subset/data/tests/iftb_requirements.tests b/test/subset/data/tests/iftb_requirements.tests
new file mode 100644
index 0000000..679b5f6
--- /dev/null
+++ b/test/subset/data/tests/iftb_requirements.tests
@@ -0,0 +1,14 @@
+FONTS:
+Roboto-Variable.ttf
+SourceSansPro-Regular.otf
+AdobeVFPrototype.otf
+
+PROFILES:
+default.txt
+iftb_requirements.txt
+
+SUBSETS:
+abc
+
+OPTIONS:
+no_fonttools
diff --git a/test/subset/data/tests/instantiate_base.tests b/test/subset/data/tests/instantiate_base.tests
new file mode 100644
index 0000000..384ea7e
--- /dev/null
+++ b/test/subset/data/tests/instantiate_base.tests
@@ -0,0 +1,15 @@
+FONTS:
+NotoSerifHK-subset.ttf
+
+PROFILES:
+default.txt
+
+SUBSETS:
+*
+
+INSTANCES:
+wght=500
+wght=400:600
+
+OPTIONS:
+no_fonttools
diff --git a/test/subset/data/tests/instantiate_colrv1.tests b/test/subset/data/tests/instantiate_colrv1.tests
index fae81b3..183bae8 100644
--- a/test/subset/data/tests/instantiate_colrv1.tests
+++ b/test/subset/data/tests/instantiate_colrv1.tests
@@ -1,14 +1,17 @@
 FONTS:
 Foldit.ttf
+KalniaGlaze.ttf
 
 PROFILES:
 default.txt
 
 SUBSETS:
+A
 *
 
 INSTANCES:
 wght=900
+wght=300:600
 
 OPTIONS:
 no_fonttools
diff --git a/test/subset/data/tests/layout.empty_ligature_offset.tests b/test/subset/data/tests/layout.empty_ligature_offset.tests
new file mode 100644
index 0000000..8d504c0
--- /dev/null
+++ b/test/subset/data/tests/layout.empty_ligature_offset.tests
@@ -0,0 +1,8 @@
+FONTS:
+AnekBangla-latin-subset.ttf
+
+PROFILES:
+default.txt
+
+SUBSETS:
+*
diff --git a/test/subset/data/tests/mvar_partial_instance.tests b/test/subset/data/tests/mvar_partial_instance.tests
index edf9296..55ef2a2 100644
--- a/test/subset/data/tests/mvar_partial_instance.tests
+++ b/test/subset/data/tests/mvar_partial_instance.tests
@@ -2,7 +2,7 @@
 NotoSans-VF.abc.ttf
 
 PROFILES:
-no-tables-with-item-variations.txt
+default.txt
 
 SUBSETS:
 *
@@ -11,3 +11,11 @@
 wght=300:600
 wght=500:800
 wght=200:600,wdth=80:90,CTGR=20:60
+
+IUP_OPTIONS:
+Yes
+No
+
+OPTIONS:
+no_fonttools
+# TODO: re-enable fonttools once rounding issues are fixed (https://github.com/harfbuzz/harfbuzz/issues/4642)
diff --git a/test/subset/data/tests/post_apply_mvar_delta.tests b/test/subset/data/tests/post_apply_mvar_delta.tests
index 82b819a..f6ddab8 100644
--- a/test/subset/data/tests/post_apply_mvar_delta.tests
+++ b/test/subset/data/tests/post_apply_mvar_delta.tests
@@ -8,4 +8,4 @@
 *
 
 INSTANCES:
-wght=400,CASL=0,CRSV=0,MONO=0,slnt=0
+wght=500,CASL=0,CRSV=0,MONO=0,slnt=0
diff --git a/test/subset/data/tests/subset_base.tests b/test/subset/data/tests/subset_base.tests
new file mode 100644
index 0000000..1399ecd
--- /dev/null
+++ b/test/subset/data/tests/subset_base.tests
@@ -0,0 +1,10 @@
+FONTS:
+SourceSansPro-Regular.otf
+
+PROFILES:
+retain-base-table.txt
+retain-base-table-filter-scripts.txt
+
+SUBSETS:
+abc
+
diff --git a/test/subset/data/tests/sync_vmetrics.tests b/test/subset/data/tests/sync_vmetrics.tests
new file mode 100644
index 0000000..3f10843
--- /dev/null
+++ b/test/subset/data/tests/sync_vmetrics.tests
@@ -0,0 +1,15 @@
+FONTS:
+playwrite_mm.subset.ttf
+
+PROFILES:
+default.txt
+
+SUBSETS:
+*
+
+INSTANCES:
+SPED=25,YEXT=520,wght=100:400,slnt=18
+
+IUP_OPTIONS:
+Yes
+No
diff --git a/test/subset/data/tests/update_def_wght.tests b/test/subset/data/tests/update_def_wght.tests
index 9ff5fce..72882a0 100644
--- a/test/subset/data/tests/update_def_wght.tests
+++ b/test/subset/data/tests/update_def_wght.tests
@@ -2,7 +2,7 @@
 SourceSerifVariable-Roman.ttf
 
 PROFILES:
-no-tables-with-item-variations.txt
+default.txt
 
 SUBSETS:
 *
@@ -10,3 +10,11 @@
 INSTANCES:
 wght=300:600
 wght=500:800
+
+IUP_OPTIONS:
+Yes
+No
+
+OPTIONS:
+no_fonttools
+# TODO: re-enable fonttools once rounding issues are fixed (https://github.com/harfbuzz/harfbuzz/issues/4642)
diff --git a/test/subset/data/tests/value_format_partial_instance.tests b/test/subset/data/tests/value_format_partial_instance.tests
new file mode 100644
index 0000000..4d5aae9
--- /dev/null
+++ b/test/subset/data/tests/value_format_partial_instance.tests
@@ -0,0 +1,16 @@
+FONTS:
+NotoSansOriya-valueformat-subset.ttf
+
+PROFILES:
+default.txt
+drop-hints.txt
+
+SUBSETS:
+*
+
+INSTANCES:
+wght=400
+
+IUP_OPTIONS:
+Yes
+No
diff --git a/test/subset/generate-expected-outputs.py b/test/subset/generate-expected-outputs.py
index 4e37562..65f3f3a 100755
--- a/test/subset/generate-expected-outputs.py
+++ b/test/subset/generate-expected-outputs.py
@@ -27,16 +27,17 @@
 		       ttx_string, count=1)
 
 
-def generate_expected_output(input_file, unicodes, profile_flags, instance_flags, output_directory, font_name, no_fonttools):
+def generate_expected_output(input_file, unicodes, profile_flags, instance_flags, iup_optimize, output_directory, font_name, no_fonttools):
 	input_path = input_file
 	if not no_fonttools and instance_flags:
 		instance_path = os.path.join(tempfile.mkdtemp (), font_name)
 		args = ["fonttools", "varLib.instancer",
 			"--no-overlap-flag",
-			"--no-recalc-timestamp",
-			"--no-optimize",
-			"--output=%s" % instance_path,
-			input_file]
+			"--no-recalc-timestamp"]
+		if not iup_optimize:
+			args.extend(["--no-optimize",])
+		args.extend(["--output=%s" % instance_path,
+			    input_file])
 		args.extend(instance_flags)
 		check_call(args)
 		input_path = instance_path
@@ -44,8 +45,8 @@
 	fonttools_path = os.path.join(tempfile.mkdtemp (), font_name)
 	args = ["fonttools", "subset", input_path]
 	if instance_flags:
-		args.extend(["--recalc-bounds"])
-	args.extend(["--drop-tables+=DSIG",
+		args.extend(["--recalc-bounds", "--recalc-average-width"])
+	args.extend(["--drop-tables+=DSIG,BASE",
 		     "--drop-tables-=sbix",
 		     "--no-harfbuzz-repacker", # disable harfbuzz repacker so we aren't comparing to ourself.
 		     "--output-file=%s" % fonttools_path])
@@ -55,6 +56,8 @@
 	# --gid-map is unsupported in fonttools so don't send it. Tests using
 	# it are crafted to work without fonttools knowing about the flag.
 	args.extend([f for f in profile_flags if not f.startswith("--gid-map")])
+	# Harfbuzz doesn't support pruning codepage ranges, so disable it in fonttools.
+	args.extend(["--no-prune-codepage-ranges"])
 	if not no_fonttools:
 		check_call(args)
 
@@ -68,13 +71,15 @@
 		hb_subset,
 		"--font-file=" + input_file,
 		"--output-file=" + harfbuzz_path,
-		"--drop-tables+=DSIG",
+		"--drop-tables+=DSIG,BASE",
 		"--drop-tables-=sbix"]
 	if unicodes != "":
 		args.extend(["--unicodes=%s" % unicodes,])
 	args.extend(profile_flags)
 	if instance_flags:
 		args.extend(["--instance=%s" % ','.join(instance_flags)])
+	if iup_optimize:
+		args.extend(["--optimize",])
 	check_call(args)
 
 	with io.StringIO () as fp:
@@ -111,4 +116,4 @@
 			no_fonttools = ("no_fonttools" in test.options)
 			print("Creating subset %s/%s" % (output_directory, font_name))
 			generate_expected_output(test.font_path, unicodes, test.get_profile_flags(),
-						 test.get_instance_flags(), output_directory, font_name, no_fonttools=no_fonttools)
+						 test.get_instance_flags(), test.iup_optimize, output_directory, font_name, no_fonttools=no_fonttools)
diff --git a/test/subset/meson.build b/test/subset/meson.build
index 827528a..b94464e 100644
--- a/test/subset/meson.build
+++ b/test/subset/meson.build
@@ -42,10 +42,11 @@
   'colr_glyphs',
   'math',
   'math_coverage_offset',
+  'subset_base',
   # TODO: re-enable once colrv1 subsetting is stabilized.
   # 'colrv1.notoemoji',
   'colrv1',
-  'colrv1_copy_varstore',
+  'colrv1_subset_varstore',
   'colr_with_components',
   'cbdt',
   'variable',
@@ -54,6 +55,8 @@
   'post',
   '32bit_var_store',
   'pin_all_at_default',
+  'instantiate_base',
+  'instantiate_colrv1',
   'instantiate_glyf',
   'instantiate_cff2',
   'full_instance',
@@ -64,16 +67,23 @@
   'post_apply_mvar_delta',
   'apply_cvar_delta',
   'collect_name_ids',
-  'instantiate_colrv1',
   'instantiate_cff2_update_metrics',
+  'layout.empty_ligature_offset',
+  'glyf_partial_instancing',
+  'mvar_partial_instance',
+  'update_def_wght',
+  'feature_variations_partial_instance',
+  'gdef_partial_instance',
+  'value_format_partial_instance',
+  'feature_variation_instance_collect_lookups',
+  'sync_vmetrics',
+  'empty_region_vardata',
 ]
 
 if get_option('experimental_api')
   tests += [
-    'glyf_partial_instancing',
-    'mvar_partial_instance',
-    'update_def_wght',
-    ]
+    'iftb_requirements',
+  ]
 endif
 
 repack_tests = [
diff --git a/test/subset/run-tests.py b/test/subset/run-tests.py
index db3c042..9e09d95 100755
--- a/test/subset/run-tests.py
+++ b/test/subset/run-tests.py
@@ -52,7 +52,7 @@
 	cli_args = ["--font-file=" + test.font_path,
 		    "--output-file=" + out_file,
 		    "--unicodes=%s" % test.unicodes (),
-		    "--drop-tables+=DSIG",
+		    "--drop-tables+=DSIG,BASE",
 		    "--drop-tables-=sbix"]
 	if preprocess:
 		cli_args.extend(["--preprocess-face",])
@@ -60,6 +60,8 @@
 	cli_args.extend (test.get_profile_flags ())
 	if test.get_instance_flags ():
 		cli_args.extend (["--instance=%s" % ','.join(test.get_instance_flags ())])
+	if test.iup_optimize:
+		cli_args.extend (["--optimize",])
 	ret = subset_cmd (cli_args)
 
 	if ret != "success":
diff --git a/test/subset/subset_test_suite.py b/test/subset/subset_test_suite.py
index b755e4e..f4cf7c1 100644
--- a/test/subset/subset_test_suite.py
+++ b/test/subset/subset_test_suite.py
@@ -5,11 +5,12 @@
 # A single test in a subset test suite. Identifies a font
 # a subsetting profile, and a subset to be cut.
 class Test:
-	def __init__(self, font_path, profile_path, subset, instance, options):
+	def __init__(self, font_path, profile_path, subset, instance, iup_optimize, options):
 		self.font_path = font_path
 		self.profile_path = profile_path
 		self.subset = subset
 		self.instance = instance
+		self.iup_optimize = iup_optimize
 		self.options = options
 
 	def unicodes(self):
@@ -29,6 +30,8 @@
 			return self.instance
 		else:
 			s = "." + self.instance.replace(':', '-')
+			if self.iup_optimize:
+				s += ".iup_optimize"
 			return s
 
 	def get_profile_flags(self):
@@ -47,7 +50,7 @@
 		profile_name = os.path.splitext(os.path.basename(self.profile_path))[0]
 
 		if self.unicodes() == "*":
-			return "%s.%s.retain-all-codepoint%s%s" % (font_base_name_parts[0],
+			return "%s.%s.all%s%s" % (font_base_name_parts[0],
 				       profile_name,
 				       self.instance_name(),
 				       font_base_name_parts[1])
@@ -79,6 +82,7 @@
 		self.subsets = []
 		self.instances = []
 		self.options = []
+		self.iup_options = []
 		self._parse(definition)
 
 	def get_output_directory(self):
@@ -101,9 +105,13 @@
 				for subset in self.subsets:
 					if self.instances:
 						for instance in self.instances:
-							yield Test(font, profile, subset, instance, options=self.options)
+							if self.iup_options:
+								for iup_option in self.iup_options:
+									yield Test(font, profile, subset, instance, iup_option == 'Yes', options=self.options)
+							else:
+								yield Test(font, profile, subset, instance, False, options=self.options)
 					else:
-						yield Test(font, profile, subset, "", options=self.options)
+						yield Test(font, profile, subset, "", False, options=self.options)
 
 	def _base_path(self):
 		return os.path.dirname(os.path.dirname(self.test_path))
@@ -115,6 +123,7 @@
 				"SUBSETS:": self.subsets,
 				"INSTANCES:": self.instances,
 				"OPTIONS:": self.options,
+				"IUP_OPTIONS:": self.iup_options,
 		}
 
 		current_destination = None
diff --git a/util/Makefile.am b/util/Makefile.am
index ca6f438..2f64b6c 100644
--- a/util/Makefile.am
+++ b/util/Makefile.am
@@ -6,7 +6,7 @@
 DISTCLEANFILES =
 MAINTAINERCLEANFILES =
 
-EXTRA_DIST += meson.build
+EXTRA_DIST += meson.build test-hb-subset-parsing.c
 
 include Makefile.sources
 
diff --git a/util/Makefile.sources b/util/Makefile.sources
index a64099e..4459b0c 100644
--- a/util/Makefile.sources
+++ b/util/Makefile.sources
@@ -47,6 +47,7 @@
 	options.hh \
 	output-options.hh \
 	text-options.hh \
+	helper-subset.hh \
 	$(NULL)
 
 HB_OT_SHAPE_CLOSURE_sources = \
diff --git a/util/hb-subset.cc b/util/hb-subset.cc
index bd3df8f..624bb1f 100644
--- a/util/hb-subset.cc
+++ b/util/hb-subset.cc
@@ -27,8 +27,10 @@
 
 #include "batch.hh"
 #include "face-options.hh"
+#include "glib.h"
 #include "main-font-text.hh"
 #include "output-options.hh"
+#include "helper-subset.hh"
 
 #include <hb-subset.h>
 
@@ -674,6 +676,7 @@
 }
 
 #ifndef HB_NO_VAR
+
 static gboolean
 parse_instance (const char *name,
 		const char *arg,
@@ -686,113 +689,7 @@
     return true;
   }
 
-  char *s = strtok((char *) arg, "=");
-  while (s)
-  {
-    unsigned len = strlen (s);
-    if (len > 4)  //Axis tags are 4 bytes.
-    {
-      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
-		   "Failed parsing axis tag at: '%s'", s);
-      return false;
-    }
-
-    hb_tag_t axis_tag = hb_tag_from_string (s, len);
-
-    s = strtok(nullptr, ", ");
-    if (!s)
-    {
-      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
-		   "Value not specified for axis: %c%c%c%c", HB_UNTAG (axis_tag));
-      return false;
-    }
-
-#ifdef HB_EXPERIMENTAL_API
-    char *pp = s;
-    pp = strpbrk (pp, ":");
-    if (pp) // partial instancing
-    {
-      errno = 0;
-      char *pend;
-      float min_val = strtof (s, &pend);
-      if (errno || s == pend || pend != pp)
-      {
-        g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
-                     "Failed parsing axis value at: '%s'", s);
-        return false;
-      }
-      pp++;
-      float max_val = strtof (pp, &pend);
-      /* we need to specify 2 values or 3 values for partial instancing:
-       * at least new min and max values, new default is optional */
-      if (errno || pp == pend || (*pend != ':' && *pend != '\0'))
-      {
-        g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
-                     "Failed parsing axis value at: '%s'", s);
-        return false;
-      }
-      /* 3 values are specified */
-      float *def_val_p = nullptr;
-      float def_val;
-      if (*pend == ':')
-      {
-        def_val = max_val;
-        def_val_p = &def_val;
-        pp = pend + 1;
-        max_val = strtof (pp, &pend);
-        if (errno || pp == pend || *pend != '\0')
-        {
-          g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
-                     "Failed parsing axis value at: '%s'", s);
-          return false;
-        }
-      }
-      if (!hb_subset_input_set_axis_range (subset_main->input, subset_main->face, axis_tag, min_val, max_val, def_val_p))
-        {
-          g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
-                       "Error: axis: '%c%c%c%c', not present in fvar or invalid range with min:%.6f max:%.6f",
-                       HB_UNTAG (axis_tag), min_val, max_val);
-          return false;
-        }
-    }
-    else
-    {
-#endif
-      if (strcmp (s, "drop") == 0)
-      {
-        if (!hb_subset_input_pin_axis_to_default (subset_main->input, subset_main->face, axis_tag))
-        {
-          g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
-                       "Cannot pin axis: '%c%c%c%c', not present in fvar", HB_UNTAG (axis_tag));
-          return false;
-        }
-      }
-      else
-      {
-        errno = 0;
-        char *p;
-        float axis_value = strtof (s, &p);
-        if (errno || s == p)
-        {
-          g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
-                       "Failed parsing axis value at: '%s'", s);
-          return false;
-        }
-  
-        if (!hb_subset_input_pin_axis_location (subset_main->input, subset_main->face, axis_tag, axis_value))
-        {
-          g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
-                       "Cannot pin axis: '%c%c%c%c', not present in fvar", HB_UNTAG (axis_tag));
-          return false;
-        }
-      }
-#ifdef HB_EXPERIMENTAL_API
-    }
-#endif
-    s = strtok(nullptr, "=");
-  }
-
-  return true;
+  return parse_instancing_spec(arg, subset_main->face, subset_main->input, error);
 }
 #endif
 
@@ -1025,14 +922,15 @@
     {"drop-tables+",	0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables,	"Drop the specified tables.", "list of string table tags or *"},
     {"drop-tables-",	0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables,	"Drop the specified tables.", "list of string table tags or *"},
 #ifndef HB_NO_VAR
-    {"instance",	0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_instance,
-     "(Partially|Fully) Instantiate a variable font. A location consists of the tag of a variation axis, followed by '=', followed by a\n"
-     "number or the literal string 'drop'\n"
-     "                                                        "
-     "For example: --instance=\"wdth=100 wght=200\" or --instance=\"wdth=drop\"\n"
-     "                                                        "
-     "Note: currently only fully instancing is supported\n",
-     "list of comma separated axis-locations"},
+     {"variations",	0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_instance,
+     "(Partially|Fully) Instantiate a variable font. A location consists of the tag "
+     "of a variation axis, followed by '=', followed by a number or the literal "
+     "string 'drop'. For example: --variations=\"wdth=100 wght=200\" or --variations=\"wdth=drop\""
+     ,
+     "list of comma separated axis-locations."
+     },
+     {"instance",	0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_instance,
+     "Alias for --variations.", "list of comma separated axis-locations"},
 #endif
     {nullptr}
   };
@@ -1060,6 +958,10 @@
      "Alternative name for --preprocess.", nullptr},
     {"preprocess",		0, 0, G_OPTION_ARG_NONE, &this->preprocess,
      "If set preprocesses the face with the add accelerator option before actually subsetting.", nullptr},
+#ifdef HB_EXPERIMENTAL_API
+    {"iftb-requirements",	0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_IFTB_REQUIREMENTS>,	"Enforce requirements needed to use the subset with incremental font transfer IFTB patches.", nullptr},
+#endif
+    {"optimize",		0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS>,	"Perform IUP delta optimization on the resulting gvar table's deltas", nullptr},
     {nullptr}
   };
   add_group (flag_entries,
diff --git a/util/helper-subset.hh b/util/helper-subset.hh
new file mode 100644
index 0000000..a050d71
--- /dev/null
+++ b/util/helper-subset.hh
@@ -0,0 +1,221 @@
+/*
+ * Copyright © 2023  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): Garret Rieger
+ */
+#ifndef HELPER_SUBSET_HH
+#define HELPER_SUBSET_HH
+
+#include "glib.h"
+#include <errno.h>
+#include <math.h>
+#include <stdbool.h>
+#include "hb-subset.h"
+
+#ifndef HB_NO_VAR
+
+// Parses an axis position string and sets min, default, and max to
+// the requested values. If a value should be set to it's default value
+// then it will be set to NaN.
+static gboolean
+parse_axis_position(const char* s,
+                    float* min,
+                    float* def,
+                    float* max,
+                    gboolean* drop,
+                    GError **error)
+{
+  const char* part = strpbrk(s, ":");
+  *drop = false;
+  if (!part) {
+    // Single value.
+    if (strcmp (s, "drop") == 0)
+    {
+      *min = NAN;
+      *def = NAN;
+      *max = NAN;
+      *drop = true;
+      return true;
+    }
+
+    errno = 0;
+    char *p;
+    float axis_value = strtof (s, &p);
+    if (errno || s == p)
+    {
+      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+                   "Failed parsing axis value at: '%s'", s);
+      return false;
+    }
+
+    *min = axis_value;
+    *def = axis_value;
+    *max = axis_value;
+    return true;
+  }
+
+
+  float values[3];
+  int count = 0;
+  for (int i = 0; i < 3; i++) {
+    errno = 0;
+    count++;
+    if (!*s || part == s) {
+      values[i] = NAN;
+
+      if (part == NULL) break;
+      s = part + 1;
+      part = strpbrk(s, ":");
+      continue;
+    }
+
+    char *pend;
+    values[i] = strtof (s, &pend);
+    if (errno || s == pend || (part && pend != part))
+    {
+      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+                   "Failed parsing axis value at: '%s'", s);
+      return false;
+    }
+
+    if (part == NULL) break;
+    s = pend + 1;
+    part = strpbrk(s, ":");
+  }
+
+  if (count == 2) {
+    *min = values[0];
+    *def = NAN;
+    *max = values[1];
+    return true;
+  } else if (count == 3) {
+    *min = values[0];
+    *def = values[1];
+    *max = values[2];
+    return true;
+  }
+
+  g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+                   "Failed parsing axis value at: '%s'", s);
+  return false;
+}
+
+static gboolean
+parse_instancing_spec (const char *arg,
+                       hb_face_t* face,
+                       hb_subset_input_t* input,
+                       GError    **error)
+{
+  char* s;
+  while ((s = strtok((char *) arg, "=")))
+  {
+    arg = NULL;
+    unsigned len = strlen (s);
+    if (len > 4)  //Axis tags are 4 bytes.
+    {
+      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+                   "Failed parsing axis tag at: '%s'", s);
+      return false;
+    }
+
+    /* support *=drop */
+    if (0 == strcmp (s, "*"))
+    {
+      s = strtok(NULL, ", ");
+      if (0 != strcmp (s, "drop"))
+      {
+        g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+                     "Failed parsing axis position at: '%s'", s);
+        return false;
+      }
+
+      if (!hb_subset_input_pin_all_axes_to_default (input, face))
+      {
+        g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+                     "Failed pinning all axes to default.");
+        return false;
+      }
+      continue;
+    }
+
+    hb_tag_t axis_tag = hb_tag_from_string (s, len);
+
+    s = strtok(NULL, ", ");
+    if (!s)
+    {
+      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+                   "Value not specified for axis: %c%c%c%c", HB_UNTAG (axis_tag));
+      return false;
+    }
+
+    gboolean drop;
+    float min, def, max;
+    if (!parse_axis_position(s, &min, &def, &max, &drop, error))
+      return false;
+
+    if (drop)
+    {
+      if (!hb_subset_input_pin_axis_to_default (input,
+                                                face,
+                                                axis_tag))
+      {
+        g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+                     "Cannot pin axis: '%c%c%c%c', not present in fvar", HB_UNTAG (axis_tag));
+        return false;
+      }
+      continue;
+    }
+
+    if (min == def && def == max) {
+      if (!hb_subset_input_pin_axis_location (input,
+                                              face, axis_tag,
+                                              def))
+      {
+        g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+                     "Cannot pin axis: '%c%c%c%c', not present in fvar", HB_UNTAG (axis_tag));
+        return false;
+      }
+      continue;
+    }
+
+    if (!hb_subset_input_set_axis_range (input,
+                                         face, axis_tag,
+                                         min, max, def))
+    {
+      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+                   "Cannot pin axis: '%c%c%c%c', not present in fvar", HB_UNTAG (axis_tag));
+      return false;
+    }
+    continue;
+
+    g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+                 "Partial instancing is not supported.");
+    return false;
+  }
+
+  return true;
+}
+
+#endif
+
+#endif
diff --git a/util/meson.build b/util/meson.build
index e857384..1f300ea 100644
--- a/util/meson.build
+++ b/util/meson.build
@@ -16,6 +16,7 @@
 
 hb_subset_cli_sources = [
   'hb-subset.cc',
+  'helper-subset.hh',
 ]
 
 util_deps = [freetype_dep, cairo_dep, cairo_ft_dep, glib_dep]
@@ -67,6 +68,21 @@
     install: true,
   )
   meson.override_find_program('hb-ot-shape-closure', hb_ot_shape_closure)
+
+  if get_option('experimental_api')
+    test('test-hb-subset-parsing',
+      executable('test-hb-subset-parsing',
+        ['test-hb-subset-parsing.c', 'helper-subset.hh'],
+        cpp_args: cpp_args,
+        c_args: ['-DHB_EXPERIMENTAL_API'],
+        include_directories: [incconfig, incsrc],
+        dependencies: util_deps,
+        link_with: [libharfbuzz, libharfbuzz_subset],
+        install: false,
+    ),
+    workdir : meson.current_source_dir(),
+    suite: ['util'])
+  endif
 else
   # Disable tests that use this
   hb_shape = disabler()
diff --git a/util/test-hb-subset-parsing.c b/util/test-hb-subset-parsing.c
new file mode 100644
index 0000000..b6b923a
--- /dev/null
+++ b/util/test-hb-subset-parsing.c
@@ -0,0 +1,111 @@
+#include <assert.h>
+#include <stdio.h>
+#include "glib.h"
+#include "hb-subset.h"
+#include "helper-subset.hh"
+
+static
+hb_face_t* open_font(const char* path)
+{
+  hb_blob_t *blob = hb_blob_create_from_file_or_fail (path);
+  g_assert(blob);
+  hb_face_t* face = hb_face_create(blob, 0);
+  hb_blob_destroy(blob);
+
+  return face;
+}
+
+static
+gboolean check_parsing(hb_face_t* face, const char* spec, hb_tag_t axis, float exp_min, float exp_def, float exp_max)
+{
+  printf(">> testing spec: %s\n", spec);
+  hb_subset_input_t* input = hb_subset_input_create_or_fail();
+  g_assert(input);
+
+  {
+    GError* error;
+    char *spec_copy = g_strdup (spec);
+    gboolean res = parse_instancing_spec(spec_copy, face, input, &error);
+    g_free(spec_copy);
+    if (!res) {
+      hb_subset_input_destroy(input);
+      return res;
+    }
+  }
+
+  float act_min = 0.0, act_def = 0.0, act_max = 0.0;
+  hb_bool_t res = hb_subset_input_get_axis_range(input, axis, &act_min, &act_max, &act_def);
+  if (!res) {
+    hb_subset_input_destroy(input);
+    return false;
+
+  }
+
+  g_assert_cmpuint(exp_min, ==, act_min);
+  g_assert_cmpuint(exp_def, ==, act_def);
+  g_assert_cmpuint(exp_max, ==, act_max);
+  
+  hb_subset_input_destroy(input);
+  return true;
+}
+
+static hb_tag_t wght = HB_TAG('w', 'g', 'h', 't');
+static hb_tag_t xxxx = HB_TAG('x', 'x', 'x', 'x');
+
+static void
+test_parse_instancing_spec (void)
+{
+  hb_face_t* face = open_font("../test/api/fonts/AdobeVFPrototype-Subset.otf");
+  hb_face_t* roboto = open_font("../test/api/fonts/Roboto-Variable.abc.ttf");
+
+  g_assert(check_parsing(face, "wght=300",         wght, 300,  300,  300));
+  g_assert(check_parsing(face, "wght=100:200:300", wght, 100,  200,  300));
+  g_assert(check_parsing(face, "wght=:500:",       wght,   0,  500, 1000));
+  g_assert(check_parsing(face, "wght=::700",       wght,   0,  700,  700));
+  g_assert(check_parsing(face, "wght=200::",       wght, 200, 1000, 1000));
+  g_assert(check_parsing(face, "wght=200:300:",    wght, 200,  300, 1000));
+  g_assert(check_parsing(face, "wght=:300:500",    wght,   0,  300,  500));
+  g_assert(check_parsing(face, "wght=300::700",    wght, 300,  700,  700));
+  g_assert(check_parsing(face, "wght=300:700",    wght,  300,  700,  700));
+  g_assert(check_parsing(face, "wght=:700",       wght,    0,  700,  700));
+  g_assert(check_parsing(face, "wght=200:",       wght,  200, 1000, 1000));
+
+  g_assert(check_parsing(face, "wght=200: xxxx=50", wght,  200, 1000, 1000));
+  g_assert(check_parsing(face, "wght=200: xxxx=50", xxxx,   50,   50,   50));
+  g_assert(check_parsing(face, "wght=200:,xxxx=50", wght,  200, 1000, 1000));
+  g_assert(check_parsing(face, "wght=200:,xxxx=50", xxxx,   50,   50,   50));
+
+  g_assert(check_parsing(face, "wght=200,*=drop", wght,  1000, 1000, 1000));
+  g_assert(check_parsing(face, "wght=200,*=drop", xxxx,  0, 0, 0));
+  g_assert(check_parsing(face, "*=drop,wght=200", wght,  200, 200, 200));
+  g_assert(check_parsing(face, "*=drop,wght=200", xxxx,  0, 0, 0));
+  g_assert(check_parsing(face, "*=drop,wght=200,xxxx=50", wght,  200, 200, 200));
+  g_assert(check_parsing(face, "*=drop,wght=200,xxxx=50", xxxx,  50, 50, 50));
+  g_assert(check_parsing(face, "xxxx=50,*=drop,wght=200", wght,  200, 200, 200));
+  g_assert(check_parsing(face, "xxxx=50,*=drop,wght=200", xxxx,  0, 0, 0));
+  g_assert(check_parsing(face, "*=drop", wght,  1000, 1000, 1000));
+  g_assert(check_parsing(face, "*=drop", xxxx,  0, 0, 0));
+
+  g_assert(check_parsing(roboto, "wght=300",         wght, 300,  300,  300));
+  g_assert(check_parsing(roboto, "wght=100:200:300", wght, 100,  200,  300));
+  g_assert(check_parsing(roboto, "wght=:500:",       wght, 100,  500,  900));
+  g_assert(check_parsing(roboto, "wght=::850",       wght, 100,  400,  850));
+  g_assert(check_parsing(roboto, "wght=200::",       wght, 200,  400,  900));
+  g_assert(check_parsing(roboto, "wght=200:300:",    wght, 200,  300,  900));
+  g_assert(check_parsing(roboto, "wght=:300:500",    wght, 100,  300,  500));
+  g_assert(check_parsing(roboto, "wght=300::700",    wght, 300,  400,  700));
+  g_assert(check_parsing(roboto, "wght=300:700",    wght,  300,  400,  700));
+  g_assert(check_parsing(roboto, "wght=:700",       wght,  100,  400,  700));
+  g_assert(check_parsing(roboto, "wght=200:",       wght,  200,  400,  900));
+
+  hb_face_destroy(face);
+}
+
+
+int
+main (int argc, char **argv)
+{
+  test_parse_instancing_spec();
+  
+  return 0;
+}
diff --git a/xkcd.png b/xkcd.png
new file mode 100644
index 0000000..8425662
--- /dev/null
+++ b/xkcd.png
Binary files differ