Merge pull request #4368 from googlefonts/support_gvar

Initial implementation for gvar partial instancing
diff --git a/.ci/requirements-fonttools.txt b/.ci/requirements-fonttools.txt
index 345c41b..754a2c8 100644
--- a/.ci/requirements-fonttools.txt
+++ b/.ci/requirements-fonttools.txt
@@ -4,39 +4,39 @@
 #
 #    pip-compile --generate-hashes .ci/requirements-fonttools.in
 #
-fonttools==4.41.1 \
-    --hash=sha256:1df1b6f4c7c4bc8201eb47f3b268adbf2539943aa43c400f84556557e3e109c0 \
-    --hash=sha256:2a22b2c425c698dcd5d6b0ff0b566e8e9663172118db6fd5f1941f9b8063da9b \
-    --hash=sha256:33191f062549e6bb1a4782c22a04ebd37009c09360e2d6686ac5083774d06d95 \
-    --hash=sha256:38cdecd8f1fd4bf4daae7fed1b3170dfc1b523388d6664b2204b351820aa78a7 \
-    --hash=sha256:3ae64303ba670f8959fdaaa30ba0c2dabe75364fdec1caeee596c45d51ca3425 \
-    --hash=sha256:3d1f9471134affc1e3b1b806db6e3e2ad3fa99439e332f1881a474c825101096 \
-    --hash=sha256:4e3334d51f0e37e2c6056e67141b2adabc92613a968797e2571ca8a03bd64773 \
-    --hash=sha256:4edc795533421e98f60acee7d28fc8d941ff5ac10f44668c9c3635ad72ae9045 \
-    --hash=sha256:547ab36a799dded58a46fa647266c24d0ed43a66028cd1cd4370b246ad426cac \
-    --hash=sha256:59eba8b2e749a1de85760da22333f3d17c42b66e03758855a12a2a542723c6e7 \
-    --hash=sha256:704bccd69b0abb6fab9f5e4d2b75896afa48b427caa2c7988792a2ffce35b441 \
-    --hash=sha256:73ef0bb5d60eb02ba4d3a7d23ada32184bd86007cb2de3657cfcb1175325fc83 \
-    --hash=sha256:7763316111df7b5165529f4183a334aa24c13cdb5375ffa1dc8ce309c8bf4e5c \
-    --hash=sha256:849ec722bbf7d3501a0e879e57dec1fc54919d31bff3f690af30bb87970f9784 \
-    --hash=sha256:891cfc5a83b0307688f78b9bb446f03a7a1ad981690ac8362f50518bc6153975 \
-    --hash=sha256:952cb405f78734cf6466252fec42e206450d1a6715746013f64df9cbd4f896fa \
-    --hash=sha256:a7bbb290d13c6dd718ec2c3db46fe6c5f6811e7ea1e07f145fd8468176398224 \
-    --hash=sha256:a9b3cc10dc9e0834b6665fd63ae0c6964c6bc3d7166e9bc84772e0edd09f9fa2 \
-    --hash=sha256:aaaef294d8e411f0ecb778a0aefd11bb5884c9b8333cc1011bdaf3b58ca4bd75 \
-    --hash=sha256:afce2aeb80be72b4da7dd114f10f04873ff512793d13ce0b19d12b2a4c44c0f0 \
-    --hash=sha256:b0938ebbeccf7c80bb9a15e31645cf831572c3a33d5cc69abe436e7000c61b14 \
-    --hash=sha256:b2d1ee95be42b80d1f002d1ee0a51d7a435ea90d36f1a5ae331be9962ee5a3f1 \
-    --hash=sha256:b927e5f466d99c03e6e20961946314b81d6e3490d95865ef88061144d9f62e38 \
-    --hash=sha256:bdd729744ae7ecd7f7311ad25d99da4999003dcfe43b436cf3c333d4e68de73d \
-    --hash=sha256:c2071267deaa6d93cb16288613419679c77220543551cbe61da02c93d92df72f \
-    --hash=sha256:cac73bbef7734e78c60949da11c4903ee5837168e58772371bd42a75872f4f82 \
-    --hash=sha256:da2c2964bdc827ba6b8a91dc6de792620be4da3922c4cf0599f36a488c07e2b2 \
-    --hash=sha256:e16a9449f21a93909c5be2f5ed5246420f2316e94195dbfccb5238aaa38f9751 \
-    --hash=sha256:e5c2b0a95a221838991e2f0e455dec1ca3a8cc9cd54febd68cc64d40fdb83669 \
-    --hash=sha256:ec453a45778524f925a8f20fd26a3326f398bfc55d534e37bab470c5e415caa1 \
-    --hash=sha256:edee0900cf0eedb29d17c7876102d6e5a91ee333882b1f5abc83e85b934cadb5 \
-    --hash=sha256:f14f3ccea4cc7dd1b277385adf3c3bf18f9860f87eab9c2fb650b0af16800f55 \
-    --hash=sha256:f240d9adf0583ac8fc1646afe7f4ac039022b6f8fa4f1575a2cfa53675360b69 \
-    --hash=sha256:f48602c0b3fd79cd83a34c40af565fe6db7ac9085c8823b552e6e751e3a5b8be
+fonttools==4.42.1 \
+    --hash=sha256:0eb79a2da5eb6457a6f8ab904838454accc7d4cccdaff1fd2bd3a0679ea33d64 \
+    --hash=sha256:113337c2d29665839b7d90b39f99b3cac731f72a0eda9306165a305c7c31d341 \
+    --hash=sha256:12a7c247d1b946829bfa2f331107a629ea77dc5391dfd34fdcd78efa61f354ca \
+    --hash=sha256:179737095eb98332a2744e8f12037b2977f22948cf23ff96656928923ddf560a \
+    --hash=sha256:19b7db825c8adee96fac0692e6e1ecd858cae9affb3b4812cdb9d934a898b29e \
+    --hash=sha256:37983b6bdab42c501202500a2be3a572f50d4efe3237e0686ee9d5f794d76b35 \
+    --hash=sha256:3a35981d90feebeaef05e46e33e6b9e5b5e618504672ca9cd0ff96b171e4bfff \
+    --hash=sha256:46a0ec8adbc6ff13494eb0c9c2e643b6f009ce7320cf640de106fb614e4d4360 \
+    --hash=sha256:4aa79366e442dbca6e2c8595645a3a605d9eeabdb7a094d745ed6106816bef5d \
+    --hash=sha256:515607ec756d7865f23070682622c49d922901943697871fc292277cf1e71967 \
+    --hash=sha256:53eb5091ddc8b1199330bb7b4a8a2e7995ad5d43376cadce84523d8223ef3136 \
+    --hash=sha256:5d18fc642fd0ac29236ff88ecfccff229ec0386090a839dd3f1162e9a7944a40 \
+    --hash=sha256:5fb289b7a815638a7613d46bcf324c9106804725b2bb8ad913c12b6958ffc4ec \
+    --hash=sha256:62f481ac772fd68901573956231aea3e4b1ad87b9b1089a61613a91e2b50bb9b \
+    --hash=sha256:689508b918332fb40ce117131633647731d098b1b10d092234aa959b4251add5 \
+    --hash=sha256:68a02bbe020dc22ee0540e040117535f06df9358106d3775e8817d826047f3fd \
+    --hash=sha256:6ed2662a3d9c832afa36405f8748c250be94ae5dfc5283d668308391f2102861 \
+    --hash=sha256:7286aed4ea271df9eab8d7a9b29e507094b51397812f7ce051ecd77915a6e26b \
+    --hash=sha256:7cc7d685b8eeca7ae69dc6416833fbfea61660684b7089bca666067cb2937dcf \
+    --hash=sha256:8708b98c278012ad267ee8a7433baeb809948855e81922878118464b274c909d \
+    --hash=sha256:9398f244e28e0596e2ee6024f808b06060109e33ed38dcc9bded452fd9bbb853 \
+    --hash=sha256:9e36344e48af3e3bde867a1ca54f97c308735dd8697005c2d24a86054a114a71 \
+    --hash=sha256:a398bdadb055f8de69f62b0fc70625f7cbdab436bbb31eef5816e28cab083ee8 \
+    --hash=sha256:acb47f6f8680de24c1ab65ebde39dd035768e2a9b571a07c7b8da95f6c8815fd \
+    --hash=sha256:be24fcb80493b2c94eae21df70017351851652a37de514de553435b256b2f249 \
+    --hash=sha256:c391cd5af88aacaf41dd7cfb96eeedfad297b5899a39e12f4c2c3706d0a3329d \
+    --hash=sha256:c95b0724a6deea2c8c5d3222191783ced0a2f09bd6d33f93e563f6f1a4b3b3a4 \
+    --hash=sha256:c9b1ce7a45978b821a06d375b83763b27a3a5e8a2e4570b3065abad240a18760 \
+    --hash=sha256:db372213d39fa33af667c2aa586a0c1235e88e9c850f5dd5c8e1f17515861868 \
+    --hash=sha256:db55cbaea02a20b49fefbd8e9d62bd481aaabe1f2301dabc575acc6b358874fa \
+    --hash=sha256:ed1a13a27f59d1fc1920394a7f596792e9d546c9ca5a044419dca70c37815d7c \
+    --hash=sha256:f2b82f46917d8722e6b5eafeefb4fb585d23babd15d8246c664cd88a5bddd19c \
+    --hash=sha256:f2f806990160d1ce42d287aa419df3ffc42dfefe60d473695fb048355fe0c6a0 \
+    --hash=sha256:f720fa82a11c0f9042376fd509b5ed88dab7e3cd602eee63a1af08883b37342b
     # via -r requirements-fonttools.in
diff --git a/.ci/requirements.in b/.ci/requirements.in
index 6288c6b..72fe697 100644
--- a/.ci/requirements.in
+++ b/.ci/requirements.in
@@ -1,4 +1,4 @@
 -r requirements-fonttools.in
-meson==1.2.0
+meson==1.2.1
 gcovr==5.0
 ninja
diff --git a/.ci/requirements.txt b/.ci/requirements.txt
index 00c4437..173508e 100644
--- a/.ci/requirements.txt
+++ b/.ci/requirements.txt
@@ -4,41 +4,41 @@
 #
 #    pip-compile --generate-hashes .ci/requirements.in
 #
-fonttools==4.41.1 \
-    --hash=sha256:1df1b6f4c7c4bc8201eb47f3b268adbf2539943aa43c400f84556557e3e109c0 \
-    --hash=sha256:2a22b2c425c698dcd5d6b0ff0b566e8e9663172118db6fd5f1941f9b8063da9b \
-    --hash=sha256:33191f062549e6bb1a4782c22a04ebd37009c09360e2d6686ac5083774d06d95 \
-    --hash=sha256:38cdecd8f1fd4bf4daae7fed1b3170dfc1b523388d6664b2204b351820aa78a7 \
-    --hash=sha256:3ae64303ba670f8959fdaaa30ba0c2dabe75364fdec1caeee596c45d51ca3425 \
-    --hash=sha256:3d1f9471134affc1e3b1b806db6e3e2ad3fa99439e332f1881a474c825101096 \
-    --hash=sha256:4e3334d51f0e37e2c6056e67141b2adabc92613a968797e2571ca8a03bd64773 \
-    --hash=sha256:4edc795533421e98f60acee7d28fc8d941ff5ac10f44668c9c3635ad72ae9045 \
-    --hash=sha256:547ab36a799dded58a46fa647266c24d0ed43a66028cd1cd4370b246ad426cac \
-    --hash=sha256:59eba8b2e749a1de85760da22333f3d17c42b66e03758855a12a2a542723c6e7 \
-    --hash=sha256:704bccd69b0abb6fab9f5e4d2b75896afa48b427caa2c7988792a2ffce35b441 \
-    --hash=sha256:73ef0bb5d60eb02ba4d3a7d23ada32184bd86007cb2de3657cfcb1175325fc83 \
-    --hash=sha256:7763316111df7b5165529f4183a334aa24c13cdb5375ffa1dc8ce309c8bf4e5c \
-    --hash=sha256:849ec722bbf7d3501a0e879e57dec1fc54919d31bff3f690af30bb87970f9784 \
-    --hash=sha256:891cfc5a83b0307688f78b9bb446f03a7a1ad981690ac8362f50518bc6153975 \
-    --hash=sha256:952cb405f78734cf6466252fec42e206450d1a6715746013f64df9cbd4f896fa \
-    --hash=sha256:a7bbb290d13c6dd718ec2c3db46fe6c5f6811e7ea1e07f145fd8468176398224 \
-    --hash=sha256:a9b3cc10dc9e0834b6665fd63ae0c6964c6bc3d7166e9bc84772e0edd09f9fa2 \
-    --hash=sha256:aaaef294d8e411f0ecb778a0aefd11bb5884c9b8333cc1011bdaf3b58ca4bd75 \
-    --hash=sha256:afce2aeb80be72b4da7dd114f10f04873ff512793d13ce0b19d12b2a4c44c0f0 \
-    --hash=sha256:b0938ebbeccf7c80bb9a15e31645cf831572c3a33d5cc69abe436e7000c61b14 \
-    --hash=sha256:b2d1ee95be42b80d1f002d1ee0a51d7a435ea90d36f1a5ae331be9962ee5a3f1 \
-    --hash=sha256:b927e5f466d99c03e6e20961946314b81d6e3490d95865ef88061144d9f62e38 \
-    --hash=sha256:bdd729744ae7ecd7f7311ad25d99da4999003dcfe43b436cf3c333d4e68de73d \
-    --hash=sha256:c2071267deaa6d93cb16288613419679c77220543551cbe61da02c93d92df72f \
-    --hash=sha256:cac73bbef7734e78c60949da11c4903ee5837168e58772371bd42a75872f4f82 \
-    --hash=sha256:da2c2964bdc827ba6b8a91dc6de792620be4da3922c4cf0599f36a488c07e2b2 \
-    --hash=sha256:e16a9449f21a93909c5be2f5ed5246420f2316e94195dbfccb5238aaa38f9751 \
-    --hash=sha256:e5c2b0a95a221838991e2f0e455dec1ca3a8cc9cd54febd68cc64d40fdb83669 \
-    --hash=sha256:ec453a45778524f925a8f20fd26a3326f398bfc55d534e37bab470c5e415caa1 \
-    --hash=sha256:edee0900cf0eedb29d17c7876102d6e5a91ee333882b1f5abc83e85b934cadb5 \
-    --hash=sha256:f14f3ccea4cc7dd1b277385adf3c3bf18f9860f87eab9c2fb650b0af16800f55 \
-    --hash=sha256:f240d9adf0583ac8fc1646afe7f4ac039022b6f8fa4f1575a2cfa53675360b69 \
-    --hash=sha256:f48602c0b3fd79cd83a34c40af565fe6db7ac9085c8823b552e6e751e3a5b8be
+fonttools==4.42.1 \
+    --hash=sha256:0eb79a2da5eb6457a6f8ab904838454accc7d4cccdaff1fd2bd3a0679ea33d64 \
+    --hash=sha256:113337c2d29665839b7d90b39f99b3cac731f72a0eda9306165a305c7c31d341 \
+    --hash=sha256:12a7c247d1b946829bfa2f331107a629ea77dc5391dfd34fdcd78efa61f354ca \
+    --hash=sha256:179737095eb98332a2744e8f12037b2977f22948cf23ff96656928923ddf560a \
+    --hash=sha256:19b7db825c8adee96fac0692e6e1ecd858cae9affb3b4812cdb9d934a898b29e \
+    --hash=sha256:37983b6bdab42c501202500a2be3a572f50d4efe3237e0686ee9d5f794d76b35 \
+    --hash=sha256:3a35981d90feebeaef05e46e33e6b9e5b5e618504672ca9cd0ff96b171e4bfff \
+    --hash=sha256:46a0ec8adbc6ff13494eb0c9c2e643b6f009ce7320cf640de106fb614e4d4360 \
+    --hash=sha256:4aa79366e442dbca6e2c8595645a3a605d9eeabdb7a094d745ed6106816bef5d \
+    --hash=sha256:515607ec756d7865f23070682622c49d922901943697871fc292277cf1e71967 \
+    --hash=sha256:53eb5091ddc8b1199330bb7b4a8a2e7995ad5d43376cadce84523d8223ef3136 \
+    --hash=sha256:5d18fc642fd0ac29236ff88ecfccff229ec0386090a839dd3f1162e9a7944a40 \
+    --hash=sha256:5fb289b7a815638a7613d46bcf324c9106804725b2bb8ad913c12b6958ffc4ec \
+    --hash=sha256:62f481ac772fd68901573956231aea3e4b1ad87b9b1089a61613a91e2b50bb9b \
+    --hash=sha256:689508b918332fb40ce117131633647731d098b1b10d092234aa959b4251add5 \
+    --hash=sha256:68a02bbe020dc22ee0540e040117535f06df9358106d3775e8817d826047f3fd \
+    --hash=sha256:6ed2662a3d9c832afa36405f8748c250be94ae5dfc5283d668308391f2102861 \
+    --hash=sha256:7286aed4ea271df9eab8d7a9b29e507094b51397812f7ce051ecd77915a6e26b \
+    --hash=sha256:7cc7d685b8eeca7ae69dc6416833fbfea61660684b7089bca666067cb2937dcf \
+    --hash=sha256:8708b98c278012ad267ee8a7433baeb809948855e81922878118464b274c909d \
+    --hash=sha256:9398f244e28e0596e2ee6024f808b06060109e33ed38dcc9bded452fd9bbb853 \
+    --hash=sha256:9e36344e48af3e3bde867a1ca54f97c308735dd8697005c2d24a86054a114a71 \
+    --hash=sha256:a398bdadb055f8de69f62b0fc70625f7cbdab436bbb31eef5816e28cab083ee8 \
+    --hash=sha256:acb47f6f8680de24c1ab65ebde39dd035768e2a9b571a07c7b8da95f6c8815fd \
+    --hash=sha256:be24fcb80493b2c94eae21df70017351851652a37de514de553435b256b2f249 \
+    --hash=sha256:c391cd5af88aacaf41dd7cfb96eeedfad297b5899a39e12f4c2c3706d0a3329d \
+    --hash=sha256:c95b0724a6deea2c8c5d3222191783ced0a2f09bd6d33f93e563f6f1a4b3b3a4 \
+    --hash=sha256:c9b1ce7a45978b821a06d375b83763b27a3a5e8a2e4570b3065abad240a18760 \
+    --hash=sha256:db372213d39fa33af667c2aa586a0c1235e88e9c850f5dd5c8e1f17515861868 \
+    --hash=sha256:db55cbaea02a20b49fefbd8e9d62bd481aaabe1f2301dabc575acc6b358874fa \
+    --hash=sha256:ed1a13a27f59d1fc1920394a7f596792e9d546c9ca5a044419dca70c37815d7c \
+    --hash=sha256:f2b82f46917d8722e6b5eafeefb4fb585d23babd15d8246c664cd88a5bddd19c \
+    --hash=sha256:f2f806990160d1ce42d287aa419df3ffc42dfefe60d473695fb048355fe0c6a0 \
+    --hash=sha256:f720fa82a11c0f9042376fd509b5ed88dab7e3cd602eee63a1af08883b37342b
     # via -r requirements-fonttools.in
 gcovr==5.0 \
     --hash=sha256:1d80264cbaadff356b3dda71b8c62b3aa803e5b3eb6d526a24932cd6660a2576 \
@@ -179,9 +179,9 @@
     --hash=sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc \
     --hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2
     # via jinja2
-meson==1.2.0 \
-    --hash=sha256:10c0364edc67a1b3146f405800b300f0535f42b8736e79c744a8029a855b7c6b \
-    --hash=sha256:1c0b634fe6b6a7072e398647f1bf392048577068a5c92ae44d04085dab0ded6f
+meson==1.2.1 \
+    --hash=sha256:08f83fc17513e99cd6e82c7554c1f58af70425211887f8f9c7363b2a90209462 \
+    --hash=sha256:b1db3a153087549497ee52b1c938d2134e0338214fe14f7efd16fecd57b639f5
     # via -r requirements.in
 ninja==1.11.1 \
     --hash=sha256:1c474326e11fba3f8c2582715d79216292e327d3335367c0e87e9647a002cc4a \
diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml
index 950e4ed..05ec95f 100644
--- a/.github/workflows/linux-ci.yml
+++ b/.github/workflows/linux-ci.yml
@@ -18,7 +18,7 @@
     - name: Checkout
       uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
     - name: Setup Ccache
-      uses: hendrikmuhs/ccache-action@ca3acd2731eef11f1572ccb126356c2f9298d35e # v1.2.9
+      uses: hendrikmuhs/ccache-action@6d1841ec156c39a52b1b23a810da917ab98da1f4 # v1.2.10
       with:
         key: ${{ github.job }}-${{ runner.os }}-${{ runner.arch }}
     - name: Install Dependencies
diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml
index abf2864..c57a5f3 100644
--- a/.github/workflows/macos-ci.yml
+++ b/.github/workflows/macos-ci.yml
@@ -17,7 +17,7 @@
     - name: Checkout
       uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
     - name: Setup Ccache
-      uses: hendrikmuhs/ccache-action@ca3acd2731eef11f1572ccb126356c2f9298d35e # v1.2.9
+      uses: hendrikmuhs/ccache-action@6d1841ec156c39a52b1b23a810da917ab98da1f4 # v1.2.10
       with:
         key: ${{ github.job }}-${{ runner.os }}-${{ runner.arch }}
     - name: Install Dependencies
diff --git a/.github/workflows/msvc-ci.yml b/.github/workflows/msvc-ci.yml
index 7ef0679..518b0ae 100644
--- a/.github/workflows/msvc-ci.yml
+++ b/.github/workflows/msvc-ci.yml
@@ -30,7 +30,7 @@
     - name: Checkout
       uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
     - name: Setup Ccache
-      uses: hendrikmuhs/ccache-action@ca3acd2731eef11f1572ccb126356c2f9298d35e # v1.2.9
+      uses: hendrikmuhs/ccache-action@6d1841ec156c39a52b1b23a810da917ab98da1f4 # v1.2.10
       with:
         variant: sccache
         key: ${{ github.job }}-${{ matrix.os }}-${{ matrix.ARCH }}
diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml
index 3432dbe..3f25667 100644
--- a/.github/workflows/scorecard.yml
+++ b/.github/workflows/scorecard.yml
@@ -59,6 +59,6 @@
 
       # Upload the results to GitHub's code scanning dashboard.
       - name: "Upload to code-scanning"
-        uses: github/codeql-action/upload-sarif@0ba4244466797eb048eb91a6cd43d5c03ca8bd05 # v2.21.2
+        uses: github/codeql-action/upload-sarif@a09933a12a80f87b87005513f0abb1494c27a716 # v2.21.4
         with:
           sarif_file: results.sarif
diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt
index 46d0a16..a9307f2 100644
--- a/docs/harfbuzz-sections.txt
+++ b/docs/harfbuzz-sections.txt
@@ -244,6 +244,8 @@
 hb_paint_funcs_set_push_transform_func
 hb_paint_pop_transform_func_t
 hb_paint_funcs_set_pop_transform_func
+hb_paint_color_glyph_func_t
+hb_paint_funcs_set_color_glyph_func
 hb_paint_push_clip_glyph_func_t
 hb_paint_funcs_set_push_clip_glyph_func
 hb_paint_push_clip_rectangle_func_t
@@ -280,6 +282,7 @@
 
 hb_paint_push_transform
 hb_paint_pop_transform
+hb_paint_color_glyph
 hb_paint_push_clip_glyph
 hb_paint_push_clip_rectangle
 hb_paint_pop_clip
diff --git a/perf/benchmark-font.cc b/perf/benchmark-font.cc
index 244e06a..67e0517 100644
--- a/perf/benchmark-font.cc
+++ b/perf/benchmark-font.cc
@@ -42,6 +42,7 @@
   glyph_h_advances,
   glyph_extents,
   draw_glyph,
+  paint_glyph,
   load_face_and_shape,
 };
 
@@ -192,6 +193,17 @@
       hb_draw_funcs_destroy (draw_funcs);
       break;
     }
+    case paint_glyph:
+    {
+      hb_paint_funcs_t *paint_funcs = hb_paint_funcs_create ();
+      for (auto _ : state)
+      {
+	for (unsigned gid = 0; gid < num_glyphs; ++gid)
+	  hb_font_paint_glyph (font, gid, paint_funcs, nullptr, 0, 0);
+      }
+      hb_paint_funcs_destroy (paint_funcs);
+      break;
+    }
     case load_face_and_shape:
     {
       for (auto _ : state)
@@ -294,6 +306,7 @@
   TEST_OPERATION (glyph_h_advances, benchmark::kMicrosecond);
   TEST_OPERATION (glyph_extents, benchmark::kMicrosecond);
   TEST_OPERATION (draw_glyph, benchmark::kMicrosecond);
+  TEST_OPERATION (paint_glyph, benchmark::kMillisecond);
   TEST_OPERATION (load_face_and_shape, benchmark::kMicrosecond);
 
 #undef TEST_OPERATION
diff --git a/src/OT/Color/COLR/COLR.hh b/src/OT/Color/COLR/COLR.hh
index 76f4c08..012c381 100644
--- a/src/OT/Color/COLR/COLR.hh
+++ b/src/OT/Color/COLR/COLR.hh
@@ -53,6 +53,7 @@
 struct hb_paint_context_t :
        hb_dispatch_context_t<hb_paint_context_t>
 {
+  const char *get_name () { return "PAINT"; }
   template <typename T>
   return_t dispatch (const T &obj) { obj.paint_glyph (this); return hb_empty_t (); }
   static return_t default_return_value () { return hb_empty_t (); }
@@ -68,6 +69,8 @@
   unsigned int palette_index;
   hb_color_t foreground;
   VarStoreInstancer &instancer;
+  hb_map_t current_glyphs;
+  hb_map_t current_layers;
   int depth_left = HB_MAX_NESTING_LEVEL;
   int edge_count = HB_COLRV1_MAX_EDGE_COUNT;
 
@@ -261,6 +264,7 @@
 
   void paint_glyph (hb_paint_context_t *c) const
   {
+    TRACE_PAINT (this);
     value.paint_glyph (c, varIdxBase);
   }
 
@@ -315,6 +319,7 @@
 
   void paint_glyph (hb_paint_context_t *c) const
   {
+    TRACE_PAINT (this);
     value.paint_glyph (c, varIdxBase);
   }
 
@@ -558,6 +563,7 @@
 
   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
   {
+    TRACE_PAINT (this);
     c->funcs->push_transform (c->data,
 			      xx.to_float (c->instancer (varIdxBase, 0)),
 			      yx.to_float (c->instancer (varIdxBase, 1)),
@@ -639,6 +645,7 @@
 
   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
   {
+    TRACE_PAINT (this);
     hb_bool_t is_foreground;
     hb_color_t color;
 
@@ -693,6 +700,7 @@
 
   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
   {
+    TRACE_PAINT (this);
     hb_color_line_t cl = {
       (void *) &(this+colorLine),
       (this+colorLine).static_get_color_stops, c,
@@ -759,6 +767,7 @@
 
   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
   {
+    TRACE_PAINT (this);
     hb_color_line_t cl = {
       (void *) &(this+colorLine),
       (this+colorLine).static_get_color_stops, c,
@@ -823,6 +832,7 @@
 
   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
   {
+    TRACE_PAINT (this);
     hb_color_line_t cl = {
       (void *) &(this+colorLine),
       (this+colorLine).static_get_color_stops, c,
@@ -874,6 +884,7 @@
 
   void paint_glyph (hb_paint_context_t *c) const
   {
+    TRACE_PAINT (this);
     c->funcs->push_inverse_root_transform (c->data, c->font);
     c->funcs->push_clip_glyph (c->data, gid, c->font);
     c->funcs->push_root_transform (c->data, c->font);
@@ -946,6 +957,7 @@
 
   void paint_glyph (hb_paint_context_t *c) const
   {
+    TRACE_PAINT (this);
     (this+transform).paint_glyph (c);
     c->recurse (this+src);
     c->funcs->pop_transform (c->data);
@@ -990,6 +1002,7 @@
 
   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
   {
+    TRACE_PAINT (this);
     float ddx = dx + c->instancer (varIdxBase, 0);
     float ddy = dy + c->instancer (varIdxBase, 1);
 
@@ -1038,6 +1051,7 @@
 
   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
   {
+    TRACE_PAINT (this);
     float sx = scaleX.to_float (c->instancer (varIdxBase, 0));
     float sy = scaleY.to_float (c->instancer (varIdxBase, 1));
 
@@ -1088,6 +1102,7 @@
 
   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
   {
+    TRACE_PAINT (this);
     float sx = scaleX.to_float (c->instancer (varIdxBase, 0));
     float sy = scaleY.to_float (c->instancer (varIdxBase, 1));
     float tCenterX = centerX + c->instancer (varIdxBase, 2);
@@ -1141,6 +1156,7 @@
 
   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
   {
+    TRACE_PAINT (this);
     float s = scale.to_float (c->instancer (varIdxBase, 0));
 
     bool p1 = c->funcs->push_scale (c->data, s, s);
@@ -1188,6 +1204,7 @@
 
   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
   {
+    TRACE_PAINT (this);
     float s = scale.to_float (c->instancer (varIdxBase, 0));
     float tCenterX = centerX + c->instancer (varIdxBase, 1);
     float tCenterY = centerY + c->instancer (varIdxBase, 2);
@@ -1239,6 +1256,7 @@
 
   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
   {
+    TRACE_PAINT (this);
     float a = angle.to_float (c->instancer (varIdxBase, 0));
 
     bool p1 = c->funcs->push_rotate (c->data, a);
@@ -1286,6 +1304,7 @@
 
   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
   {
+    TRACE_PAINT (this);
     float a = angle.to_float (c->instancer (varIdxBase, 0));
     float tCenterX = centerX + c->instancer (varIdxBase, 1);
     float tCenterY = centerY + c->instancer (varIdxBase, 2);
@@ -1340,6 +1359,7 @@
 
   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
   {
+    TRACE_PAINT (this);
     float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0));
     float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1));
 
@@ -1390,6 +1410,7 @@
 
   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
   {
+    TRACE_PAINT (this);
     float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0));
     float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1));
     float tCenterX = centerX + c->instancer (varIdxBase, 2);
@@ -1442,6 +1463,7 @@
 
   void paint_glyph (hb_paint_context_t *c) const
   {
+    TRACE_PAINT (this);
     c->recurse (this+backdrop);
     c->funcs->push_group (c->data);
     c->recurse (this+src);
@@ -2287,6 +2309,7 @@
 	                         &(this+varIdxMap),
 	                         hb_array (font->coords, font->num_coords));
     hb_paint_context_t c (this, funcs, data, font, palette_index, foreground, instancer);
+    c.current_glyphs.add (glyph);
 
     if (version == 1)
     {
@@ -2402,18 +2425,42 @@
 
 void PaintColrLayers::paint_glyph (hb_paint_context_t *c) const
 {
+  TRACE_PAINT (this);
   const LayerList &paint_offset_lists = c->get_colr_table ()->get_layerList ();
   for (unsigned i = firstLayerIndex; i < firstLayerIndex + numLayers; i++)
   {
+    if (unlikely (c->current_layers.has (i)))
+      continue;
+
+    c->current_layers.add (i);
+
     const Paint &paint = paint_offset_lists.get_paint (i);
     c->funcs->push_group (c->data);
     c->recurse (paint);
     c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
+
+    c->current_layers.del (i);
   }
 }
 
 void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const
 {
+  TRACE_PAINT (this);
+
+  if (unlikely (c->current_glyphs.has (gid)))
+    return;
+
+  c->current_glyphs.add (gid);
+
+  c->funcs->push_inverse_root_transform (c->data, c->font);
+  if (c->funcs->color_glyph (c->data, gid, c->font))
+  {
+    c->funcs->pop_transform (c->data);
+    c->current_glyphs.del (gid);
+    return;
+  }
+  c->funcs->pop_transform (c->data);
+
   const COLR *colr_table = c->get_colr_table ();
   const Paint *paint = colr_table->get_base_glyph_paint (gid);
 
@@ -2432,6 +2479,8 @@
 
   if (has_clip_box)
     c->funcs->pop_clip (c->data);
+
+  c->current_glyphs.del (gid);
 }
 
 } /* namespace OT */
diff --git a/src/OT/glyf/Glyph.hh b/src/OT/glyf/Glyph.hh
index 2b2184f..5ea6119 100644
--- a/src/OT/glyf/Glyph.hh
+++ b/src/OT/glyf/Glyph.hh
@@ -350,6 +350,7 @@
 		   bool use_my_metrics = true,
 		   bool phantom_only = false,
 		   hb_array_t<int> coords = hb_array_t<int> (),
+		   hb_map_t *current_glyphs = nullptr,
 		   unsigned int depth = 0,
 		   unsigned *edge_count = nullptr) const
   {
@@ -359,6 +360,10 @@
     if (unlikely (*edge_count > HB_GLYF_MAX_EDGE_COUNT)) return false;
     (*edge_count)++;
 
+    hb_map_t current_glyphs_stack;
+    if (current_glyphs == nullptr)
+      current_glyphs = &current_glyphs_stack;
+
     if (head_maxp_info)
     {
       head_maxp_info->maxComponentDepth = hb_max (head_maxp_info->maxComponentDepth, depth);
@@ -453,10 +458,17 @@
       unsigned int comp_index = 0;
       for (auto &item : get_composite_iterator ())
       {
+	hb_codepoint_t item_gid = item.get_gid ();
+
+        if (unlikely (current_glyphs->has (item_gid)))
+	  continue;
+
+	current_glyphs->add (item_gid);
+
 	unsigned old_count = all_points.length;
 
 	if (unlikely ((!phantom_only || (use_my_metrics && item.is_use_my_metrics ())) &&
-		      !glyf_accelerator.glyph_for_gid (item.get_gid ())
+		      !glyf_accelerator.glyph_for_gid (item_gid)
 				       .get_points (font,
 						    glyf_accelerator,
 						    all_points,
@@ -467,9 +479,13 @@
 						    use_my_metrics,
 						    phantom_only,
 						    coords,
+						    current_glyphs,
 						    depth + 1,
 						    edge_count)))
+	{
+	  current_glyphs->del (item_gid);
 	  return false;
+	}
 
 	auto comp_points = all_points.as_array ().sub_array (old_count);
 
@@ -505,9 +521,13 @@
 	all_points.resize (all_points.length - PHANTOM_COUNT);
 
 	if (all_points.length > HB_GLYF_MAX_POINTS)
+	{
+	  current_glyphs->del (item_gid);
 	  return false;
+	}
 
 	comp_index++;
+        current_glyphs->del (item_gid);
       }
 
       if (head_maxp_info && depth == 0)
@@ -525,6 +545,13 @@
       hb_array_t<contour_point_t> points_left = points.as_array ();
       for (auto &item : get_var_composite_iterator ())
       {
+	hb_codepoint_t item_gid = item.get_gid ();
+
+        if (unlikely (current_glyphs->has (item_gid)))
+	  continue;
+
+	current_glyphs->add (item_gid);
+
 	unsigned item_num_points = item.get_num_points ();
 	hb_array_t<contour_point_t> record_points = points_left.sub_array (0, item_num_points);
 	assert (record_points.length == item_num_points);
@@ -542,7 +569,7 @@
 	unsigned old_count = all_points.length;
 
 	if (unlikely ((!phantom_only || (use_my_metrics && item.is_use_my_metrics ())) &&
-		      !glyf_accelerator.glyph_for_gid (item.get_gid ())
+		      !glyf_accelerator.glyph_for_gid (item_gid)
 				       .get_points (font,
 						    glyf_accelerator,
 						    all_points,
@@ -553,9 +580,13 @@
 						    use_my_metrics,
 						    phantom_only,
 						    coord_setter.get_coords (),
+						    current_glyphs,
 						    depth + 1,
 						    edge_count)))
+	{
+	  current_glyphs->del (item_gid);
 	  return false;
+	}
 
 	auto comp_points = all_points.as_array ().sub_array (old_count);
 
@@ -571,9 +602,14 @@
 	all_points.resize (all_points.length - PHANTOM_COUNT);
 
 	if (all_points.length > HB_GLYF_MAX_POINTS)
+	{
+	  current_glyphs->del (item_gid);
 	  return false;
+	}
 
 	points_left += item_num_points;
+
+        current_glyphs->del (item_gid);
       }
       all_points.extend (phantoms);
     } break;
diff --git a/src/graph/graph.hh b/src/graph/graph.hh
index 0680958..f81bed8 100644
--- a/src/graph/graph.hh
+++ b/src/graph/graph.hh
@@ -290,7 +290,7 @@
 	new_parents.set (id_map[_.first], _.second);
       }
 
-      if (new_parents.in_error ())
+      if (parents.in_error() || new_parents.in_error ())
         return false;
 
       parents = std::move (new_parents);
@@ -310,8 +310,15 @@
       if (parents.has (old_index, &pv))
       {
         unsigned v = *pv;
-	parents.set (new_index, v);
+	if (!parents.set (new_index, v))
+          incoming_edges_ -= v;
 	parents.del (old_index);
+
+        if (incoming_edges_ == 1)
+	{
+	  single_parent = *parents.keys ();
+	  parents.reset ();
+	}
       }
     }
 
diff --git a/src/hb-cairo.cc b/src/hb-cairo.cc
index 68c7bc0..f4f9f54 100644
--- a/src/hb-cairo.cc
+++ b/src/hb-cairo.cc
@@ -166,6 +166,32 @@
   cairo_restore (cr);
 }
 
+static hb_bool_t
+hb_cairo_paint_color_glyph (hb_paint_funcs_t *pfuncs HB_UNUSED,
+			    void *paint_data,
+			    hb_codepoint_t glyph,
+			    hb_font_t *font,
+			    void *user_data HB_UNUSED)
+{
+  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
+  cairo_t *cr = c->cr;
+
+  cairo_save (cr);
+
+  hb_position_t x_scale, y_scale;
+  hb_font_get_scale (font, &x_scale, &y_scale);
+  cairo_scale (cr, x_scale, y_scale);
+
+  cairo_glyph_t cairo_glyph = { glyph, 0, 0 };
+  cairo_set_scaled_font (cr, c->scaled_font);
+  cairo_set_font_size (cr, 1);
+  cairo_show_glyphs (cr, &cairo_glyph, 1);
+
+  cairo_restore (cr);
+
+  return true;
+}
+
 static void
 hb_cairo_push_clip_glyph (hb_paint_funcs_t *pfuncs HB_UNUSED,
 			  void *paint_data,
@@ -397,6 +423,7 @@
 
     hb_paint_funcs_set_push_transform_func (funcs, hb_cairo_push_transform, nullptr, nullptr);
     hb_paint_funcs_set_pop_transform_func (funcs, hb_cairo_pop_transform, nullptr, nullptr);
+    hb_paint_funcs_set_color_glyph_func (funcs, hb_cairo_paint_color_glyph, nullptr, nullptr);
     hb_paint_funcs_set_push_clip_glyph_func (funcs, hb_cairo_push_clip_glyph, nullptr, nullptr);
     hb_paint_funcs_set_push_clip_rectangle_func (funcs, hb_cairo_push_clip_rectangle, nullptr, nullptr);
     hb_paint_funcs_set_pop_clip_func (funcs, hb_cairo_pop_clip, nullptr, nullptr);
diff --git a/src/hb-common.cc b/src/hb-common.cc
index 282a8e4..bd4cd88 100644
--- a/src/hb-common.cc
+++ b/src/hb-common.cc
@@ -815,7 +815,7 @@
   }
 
   const char *p = *pp;
-  while (*pp < end && (ISALNUM(**pp) || **pp == '_'))
+  while (*pp < end && (**pp != ' ' && **pp != '=' && **pp != '['))
     (*pp)++;
 
   if (p == *pp || *pp - p > 4)
diff --git a/src/hb-debug.hh b/src/hb-debug.hh
index 6055fce..559db40 100644
--- a/src/hb-debug.hh
+++ b/src/hb-debug.hh
@@ -265,8 +265,9 @@
   }
 }
 template <>
-/*static*/ inline void _hb_warn_no_return<hb_empty_t> (bool returned HB_UNUSED)
-{}
+/*static*/ inline void _hb_warn_no_return<hb_empty_t> (bool returned HB_UNUSED) {}
+template <>
+/*static*/ inline void _hb_warn_no_return<void> (bool returned HB_UNUSED) {}
 
 template <int max_level, typename ret_t>
 struct hb_auto_trace_t
@@ -450,12 +451,26 @@
 #define HB_DEBUG_SUBSET_REPACK (HB_DEBUG+0)
 #endif
 
+#ifndef HB_DEBUG_PAINT
+#define HB_DEBUG_PAINT (HB_DEBUG+0)
+#endif
+#if HB_DEBUG_PAINT
+#define TRACE_PAINT(this) \
+  HB_UNUSED hb_auto_trace_t<HB_DEBUG_PAINT, void> trace \
+  (&c->debug_depth, c->get_name (), this, HB_FUNC, \
+   " ")
+#else
+#define TRACE_PAINT(this) HB_UNUSED hb_no_trace_t<void> trace
+#endif
+
+
 #ifndef HB_DEBUG_DISPATCH
 #define HB_DEBUG_DISPATCH ( \
 	HB_DEBUG_APPLY + \
 	HB_DEBUG_SANITIZE + \
 	HB_DEBUG_SERIALIZE + \
 	HB_DEBUG_SUBSET + \
+	HB_DEBUG_PAINT + \
 	0)
 #endif
 #if HB_DEBUG_DISPATCH
diff --git a/src/hb-ft-colr.hh b/src/hb-ft-colr.hh
index fa5712f..1afbbbb 100644
--- a/src/hb-ft-colr.hh
+++ b/src/hb-ft-colr.hh
@@ -105,6 +105,8 @@
   FT_Color *palette;
   unsigned palette_index;
   hb_color_t foreground;
+  hb_map_t current_glyphs;
+  hb_map_t current_layers;
   int depth_left = HB_MAX_NESTING_LEVEL;
   int edge_count = HB_COLRV1_MAX_EDGE_COUNT;
 };
@@ -220,9 +222,18 @@
 				  &paint.u.colr_layers.layer_iterator,
 				  &other_paint))
       {
+        unsigned i = paint.u.colr_layers.layer_iterator.layer;
+
+	if (unlikely (c->current_layers.has (i)))
+	  continue;
+
+	c->current_layers.add (i);
+
 	c->funcs->push_group (c->data);
 	c->recurse (other_paint);
 	c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
+
+	c->current_layers.del (i);
       }
     }
     break;
@@ -320,8 +331,27 @@
     break;
     case FT_COLR_PAINTFORMAT_COLR_GLYPH:
     {
+      hb_codepoint_t gid = paint.u.colr_glyph.glyphID;
+
+      if (unlikely (c->current_glyphs.has (gid)))
+	return;
+
+      c->current_glyphs.add (gid);
+
+      c->funcs->push_inverse_root_transform (c->data, c->font);
+      c->ft_font->lock.unlock ();
+      if (c->funcs->color_glyph (c->data, gid, c->font))
+      {
+	c->ft_font->lock.lock ();
+	c->funcs->pop_transform (c->data);
+	c->current_glyphs.del (gid);
+	return;
+      }
+      c->ft_font->lock.lock ();
+      c->funcs->pop_transform (c->data);
+
       FT_OpaquePaint other_paint = {0};
-      if (FT_Get_Color_Glyph_Paint (ft_face, paint.u.colr_glyph.glyphID,
+      if (FT_Get_Color_Glyph_Paint (ft_face, gid,
 				    FT_COLOR_NO_ROOT_TRANSFORM,
 				    &other_paint))
       {
@@ -350,6 +380,8 @@
 
         if (has_clip_box)
           c->funcs->pop_clip (c->data);
+
+	c->current_glyphs.del (gid);
       }
     }
     break;
@@ -474,6 +506,7 @@
     hb_ft_paint_context_t c (ft_font, font,
 			     paint_funcs, paint_data,
 			     palette, palette_index, foreground);
+    c.current_glyphs.add (gid);
 
     bool is_bounded = true;
     FT_ClipBox clip_box;
@@ -497,6 +530,7 @@
       hb_ft_paint_context_t ce (ft_font, font,
 			        extents_funcs, &extents_data,
 			        palette, palette_index, foreground);
+      ce.current_glyphs.add (gid);
       ce.funcs->push_root_transform (ce.data, font);
       ce.recurse (paint);
       ce.funcs->pop_transform (ce.data);
diff --git a/src/hb-limits.hh b/src/hb-limits.hh
index c503b30..25c1e71 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 1024
+#define HB_COLRV1_MAX_EDGE_COUNT 65536
 #endif
 
 
diff --git a/src/hb-map.hh b/src/hb-map.hh
index 42604ef..6ea4166 100644
--- a/src/hb-map.hh
+++ b/src/hb-map.hh
@@ -276,6 +276,11 @@
     uint32_t hash = hb_hash (key);
     return set_with_hash (std::move (key), hash, std::forward<VV> (value), overwrite);
   }
+  bool add (const K &key)
+  {
+    uint32_t hash = hb_hash (key);
+    return set_with_hash (key, hash, item_t::default_value ());
+  }
 
   const V& get_with_hash (const K &key, uint32_t hash) const
   {
diff --git a/src/hb-ot-shaper-arabic.cc b/src/hb-ot-shaper-arabic.cc
index 256f8f1..72dcc84 100644
--- a/src/hb-ot-shaper-arabic.cc
+++ b/src/hb-ot-shaper-arabic.cc
@@ -486,8 +486,10 @@
   if (likely (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH)))
     return;
 
-  /* The Arabic shaper currently always processes in RTL mode, so we should
-   * stretch / position the stretched pieces to the left / preceding glyphs. */
+  bool rtl = buffer->props.direction == HB_DIRECTION_RTL;
+
+  if (!rtl)
+    buffer->reverse ();
 
   /* We do a two pass implementation:
    * First pass calculates the exact number of extra glyphs we need,
@@ -577,7 +579,10 @@
 	++n_copies;
 	hb_position_t excess = (n_copies + 1) * sign * w_repeating - sign * w_remaining;
 	if (excess > 0)
+	{
 	  extra_repeat_overlap = excess / (n_copies * n_repeating);
+	  w_remaining = 0;
+	}
       }
 
       if (step == MEASURE)
@@ -588,7 +593,7 @@
       else
       {
 	buffer->unsafe_to_break (context, end);
-	hb_position_t x_offset = 0;
+	hb_position_t x_offset = w_remaining / 2;
 	for (unsigned int k = end; k > start; k--)
 	{
 	  hb_position_t width = font->get_glyph_h_advance (info[k - 1].codepoint);
@@ -599,16 +604,27 @@
 
 	  DEBUG_MSG (ARABIC, nullptr, "appending %u copies of glyph %u; j=%u",
 		     repeat, info[k - 1].codepoint, j);
+	  pos[k - 1].x_advance = 0;
 	  for (unsigned int n = 0; n < repeat; n++)
 	  {
-	    x_offset -= width;
-	    if (n > 0)
-	      x_offset += extra_repeat_overlap;
+	    if (rtl)
+	    {
+	      x_offset -= width;
+	      if (n > 0)
+		x_offset += extra_repeat_overlap;
+	    }
 	    pos[k - 1].x_offset = x_offset;
 	    /* Append copy. */
 	    --j;
 	    info[j] = info[k - 1];
 	    pos[j] = pos[k - 1];
+
+	    if (!rtl)
+	    {
+	      x_offset += width;
+	      if (n > 0)
+		x_offset -= extra_repeat_overlap;
+	    }
 	  }
 	}
       }
@@ -625,6 +641,9 @@
       buffer->len = new_len;
     }
   }
+
+  if (!rtl)
+    buffer->reverse ();
 }
 
 
diff --git a/src/hb-ot-var-common.hh b/src/hb-ot-var-common.hh
index 1d8be05..d1c617e 100644
--- a/src/hb-ot-var-common.hh
+++ b/src/hb-ot-var-common.hh
@@ -230,7 +230,7 @@
   /* according to the spec, if colr table has varStore but does not have
    * varIdxMap, then an implicit identity mapping is used */
   float operator() (uint32_t varIdx, unsigned short offset = 0) const
-  { return varStore->get_delta (varIdxMap ? varIdxMap->map (VarIdx::add (varIdx, offset)) : varIdx + offset, coords); }
+  { return coords ? varStore->get_delta (varIdxMap ? varIdxMap->map (VarIdx::add (varIdx, offset)) : varIdx + offset, coords) : 0; }
 
   const VariationStore *varStore;
   const DeltaSetIndexMap *varIdxMap;
diff --git a/src/hb-paint.cc b/src/hb-paint.cc
index 28150f1..0a53845 100644
--- a/src/hb-paint.cc
+++ b/src/hb-paint.cc
@@ -54,6 +54,12 @@
 hb_paint_pop_transform_nil (hb_paint_funcs_t *funcs, void *paint_data,
                             void *user_data) {}
 
+static hb_bool_t
+hb_paint_color_glyph_nil (hb_paint_funcs_t *funcs, void *paint_data,
+                          hb_codepoint_t glyph,
+                          hb_font_t *font,
+                          void *user_data) { return false; }
+
 static void
 hb_paint_push_clip_glyph_nil (hb_paint_funcs_t *funcs, void *paint_data,
                               hb_codepoint_t glyph,
@@ -474,6 +480,25 @@
 }
 
 /**
+ * hb_paint_color_glyph:
+ * @funcs: paint functions
+ * @paint_data: associated data passed by the caller
+ * @glyph: the glyph ID
+ * @font: the font
+ *
+ * Perform a "color-glyph" paint operation.
+ *
+ * XSince: REPLACEME
+ */
+hb_bool_t
+hb_paint_color_glyph (hb_paint_funcs_t *funcs, void *paint_data,
+                      hb_codepoint_t glyph,
+                      hb_font_t *font)
+{
+  return funcs->color_glyph (paint_data, glyph, font);
+}
+
+/**
  * hb_paint_push_clip_glyph:
  * @funcs: paint functions
  * @paint_data: associated data passed by the caller
diff --git a/src/hb-paint.h b/src/hb-paint.h
index 5433827..74f49f0 100644
--- a/src/hb-paint.h
+++ b/src/hb-paint.h
@@ -137,6 +137,26 @@
                                                void *user_data);
 
 /**
+ * hb_paint_color_glyph_func_t:
+ * @funcs: paint functions object
+ * @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
+ * @glyph: the glyph ID
+ * @font: the font
+ * @user_data: User data pointer passed to hb_paint_funcs_set_color_glyph_func()
+ *
+ * A virtual method for the #hb_paint_funcs_t to render a color glyph by glyph index.
+ *
+ * Return value: %true if the glyph was painted, %false otherwise.
+ *
+ * XSince: REPLACEME
+ */
+typedef hb_bool_t (*hb_paint_color_glyph_func_t) (hb_paint_funcs_t *funcs,
+                                                  void *paint_data,
+                                                  hb_codepoint_t glyph,
+                                                  hb_font_t *font,
+                                                  void *user_data);
+
+/**
  * hb_paint_push_clip_glyph_func_t:
  * @funcs: paint functions object
  * @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
@@ -724,6 +744,23 @@
                                        hb_destroy_func_t              destroy);
 
 /**
+ * hb_paint_funcs_set_color_glyph_func:
+ * @funcs: A paint functions struct
+ * @func: (closure user_data) (destroy destroy) (scope notified): The color-glyph callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): Function to call when @user_data is no longer needed
+ *
+ * Sets the color-glyph callback on the paint functions struct.
+ *
+ * Since: 7.0.0
+ */
+HB_EXTERN void
+hb_paint_funcs_set_color_glyph_func (hb_paint_funcs_t                *funcs,
+				     hb_paint_color_glyph_func_t     func,
+				     void                            *user_data,
+				     hb_destroy_func_t                destroy);
+
+/**
  * hb_paint_funcs_set_push_clip_glyph_func:
  * @funcs: A paint functions struct
  * @func: (closure user_data) (destroy destroy) (scope notified): The push-clip-glyph callback
@@ -922,6 +959,11 @@
 HB_EXTERN void
 hb_paint_pop_transform (hb_paint_funcs_t *funcs, void *paint_data);
 
+HB_EXTERN hb_bool_t
+hb_paint_color_glyph (hb_paint_funcs_t *funcs, void *paint_data,
+                      hb_codepoint_t glyph,
+                      hb_font_t *font);
+
 HB_EXTERN void
 hb_paint_push_clip_glyph (hb_paint_funcs_t *funcs, void *paint_data,
                           hb_codepoint_t glyph,
diff --git a/src/hb-paint.hh b/src/hb-paint.hh
index d291a4b..56b790d 100644
--- a/src/hb-paint.hh
+++ b/src/hb-paint.hh
@@ -32,6 +32,7 @@
 #define HB_PAINT_FUNCS_IMPLEMENT_CALLBACKS \
   HB_PAINT_FUNC_IMPLEMENT (push_transform) \
   HB_PAINT_FUNC_IMPLEMENT (pop_transform) \
+  HB_PAINT_FUNC_IMPLEMENT (color_glyph) \
   HB_PAINT_FUNC_IMPLEMENT (push_clip_glyph) \
   HB_PAINT_FUNC_IMPLEMENT (push_clip_rectangle) \
   HB_PAINT_FUNC_IMPLEMENT (pop_clip) \
@@ -77,6 +78,13 @@
   void pop_transform (void *paint_data)
   { func.pop_transform (this, paint_data,
                         !user_data ? nullptr : user_data->pop_transform); }
+  bool color_glyph (void *paint_data,
+                    hb_codepoint_t glyph,
+                    hb_font_t *font)
+  { return func.color_glyph (this, paint_data,
+                             glyph,
+                             font,
+                             !user_data ? nullptr : user_data->push_clip_glyph); }
   void push_clip_glyph (void *paint_data,
                         hb_codepoint_t glyph,
                         hb_font_t *font)
diff --git a/test/api/results/bad-154 b/test/api/results/bad-154
index 2f4bdfc..5f88e03 100644
--- a/test/api/results/bad-154
+++ b/test/api/results/bad-154
@@ -1,351 +1,9 @@
-# random seed: R02S345aec86e0be01a834deb6fc61057f9c
+# random seed: R02S13f44c97ec7b03f792b3b9650a81b62a
 # Start of hb tests
 # Start of paint tests
 # Start of ot tests
 start clip rectangle 0 500 500 1e+03
   start transform 1 0 0 1 0 0
-    start clip rectangle 0 500 500 1e+03
-      start clip rectangle 0 500 500 1e+03
-        start clip rectangle 0 500 500 1e+03
-          start clip rectangle 0 500 500 1e+03
-            start clip rectangle 0 500 500 1e+03
-              start clip rectangle 0 500 500 1e+03
-                start clip rectangle 0 500 500 1e+03
-                  start clip rectangle 0 500 500 1e+03
-                    start clip rectangle 0 500 500 1e+03
-                      start clip rectangle 0 500 500 1e+03
-                        start clip rectangle 0 500 500 1e+03
-                          start clip rectangle 0 500 500 1e+03
-                            start clip rectangle 0 500 500 1e+03
-                              start clip rectangle 0 500 500 1e+03
-                                start clip rectangle 0 500 500 1e+03
-                                  start clip rectangle 0 500 500 1e+03
-                                    start clip rectangle 0 500 500 1e+03
-                                      start clip rectangle 0 500 500 1e+03
-                                        start clip rectangle 0 500 500 1e+03
-                                          start clip rectangle 0 500 500 1e+03
-                                            start clip rectangle 0 500 500 1e+03
-                                              start clip rectangle 0 500 500 1e+03
-                                                start clip rectangle 0 500 500 1e+03
-                                                  start clip rectangle 0 500 500 1e+03
-                                                    start clip rectangle 0 500 500 1e+03
-                                                      start clip rectangle 0 500 500 1e+03
-                                                        start clip rectangle 0 500 500 1e+03
-                                                          start clip rectangle 0 500 500 1e+03
-                                                            start clip rectangle 0 500 500 1e+03
-                                                              start clip rectangle 0 500 500 1e+03
-                                                                start clip rectangle 0 500 500 1e+03
-                                                                  start clip rectangle 0 500 500 1e+03
-                                                                  end clip
-                                                                  push group
-                                                                    start transform 1 0 -0 1 0 0
-                                                                      start clip glyph 159
-                                                                        start transform 1 0 0 1 0 0
-                                                                        end transform
-                                                                      end clip
-                                                                    end transform
-                                                                  pop group mode 3
-                                                                end clip
-                                                                push group
-                                                                  start transform 1 0 -0 1 0 0
-                                                                    start clip glyph 159
-                                                                      start transform 1 0 0 1 0 0
-                                                                        solid 128 128 128 102
-                                                                      end transform
-                                                                    end clip
-                                                                  end transform
-                                                                pop group mode 3
-                                                              end clip
-                                                              push group
-                                                                start transform 1 0 -0 1 0 0
-                                                                  start clip glyph 159
-                                                                    start transform 1 0 0 1 0 0
-                                                                      solid 128 128 128 102
-                                                                    end transform
-                                                                  end clip
-                                                                end transform
-                                                              pop group mode 3
-                                                            end clip
-                                                            push group
-                                                              start transform 1 0 -0 1 0 0
-                                                                start clip glyph 159
-                                                                  start transform 1 0 0 1 0 0
-                                                                    solid 128 128 128 102
-                                                                  end transform
-                                                                end clip
-                                                              end transform
-                                                            pop group mode 3
-                                                          end clip
-                                                          push group
-                                                            start transform 1 0 -0 1 0 0
-                                                              start clip glyph 159
-                                                                start transform 1 0 0 1 0 0
-                                                                  solid 128 128 128 102
-                                                                end transform
-                                                              end clip
-                                                            end transform
-                                                          pop group mode 3
-                                                        end clip
-                                                        push group
-                                                          start transform 1 0 -0 1 0 0
-                                                            start clip glyph 159
-                                                              start transform 1 0 0 1 0 0
-                                                                solid 128 128 128 102
-                                                              end transform
-                                                            end clip
-                                                          end transform
-                                                        pop group mode 3
-                                                      end clip
-                                                      push group
-                                                        start transform 1 0 -0 1 0 0
-                                                          start clip glyph 159
-                                                            start transform 1 0 0 1 0 0
-                                                              solid 128 128 128 102
-                                                            end transform
-                                                          end clip
-                                                        end transform
-                                                      pop group mode 3
-                                                    end clip
-                                                    push group
-                                                      start transform 1 0 -0 1 0 0
-                                                        start clip glyph 159
-                                                          start transform 1 0 0 1 0 0
-                                                            solid 128 128 128 102
-                                                          end transform
-                                                        end clip
-                                                      end transform
-                                                    pop group mode 3
-                                                  end clip
-                                                  push group
-                                                    start transform 1 0 -0 1 0 0
-                                                      start clip glyph 159
-                                                        start transform 1 0 0 1 0 0
-                                                          solid 128 128 128 102
-                                                        end transform
-                                                      end clip
-                                                    end transform
-                                                  pop group mode 3
-                                                end clip
-                                                push group
-                                                  start transform 1 0 -0 1 0 0
-                                                    start clip glyph 159
-                                                      start transform 1 0 0 1 0 0
-                                                        solid 128 128 128 102
-                                                      end transform
-                                                    end clip
-                                                  end transform
-                                                pop group mode 3
-                                              end clip
-                                              push group
-                                                start transform 1 0 -0 1 0 0
-                                                  start clip glyph 159
-                                                    start transform 1 0 0 1 0 0
-                                                      solid 128 128 128 102
-                                                    end transform
-                                                  end clip
-                                                end transform
-                                              pop group mode 3
-                                            end clip
-                                            push group
-                                              start transform 1 0 -0 1 0 0
-                                                start clip glyph 159
-                                                  start transform 1 0 0 1 0 0
-                                                    solid 128 128 128 102
-                                                  end transform
-                                                end clip
-                                              end transform
-                                            pop group mode 3
-                                          end clip
-                                          push group
-                                            start transform 1 0 -0 1 0 0
-                                              start clip glyph 159
-                                                start transform 1 0 0 1 0 0
-                                                  solid 128 128 128 102
-                                                end transform
-                                              end clip
-                                            end transform
-                                          pop group mode 3
-                                        end clip
-                                        push group
-                                          start transform 1 0 -0 1 0 0
-                                            start clip glyph 159
-                                              start transform 1 0 0 1 0 0
-                                                solid 128 128 128 102
-                                              end transform
-                                            end clip
-                                          end transform
-                                        pop group mode 3
-                                      end clip
-                                      push group
-                                        start transform 1 0 -0 1 0 0
-                                          start clip glyph 159
-                                            start transform 1 0 0 1 0 0
-                                              solid 128 128 128 102
-                                            end transform
-                                          end clip
-                                        end transform
-                                      pop group mode 3
-                                    end clip
-                                    push group
-                                      start transform 1 0 -0 1 0 0
-                                        start clip glyph 159
-                                          start transform 1 0 0 1 0 0
-                                            solid 128 128 128 102
-                                          end transform
-                                        end clip
-                                      end transform
-                                    pop group mode 3
-                                  end clip
-                                  push group
-                                    start transform 1 0 -0 1 0 0
-                                      start clip glyph 159
-                                        start transform 1 0 0 1 0 0
-                                          solid 128 128 128 102
-                                        end transform
-                                      end clip
-                                    end transform
-                                  pop group mode 3
-                                end clip
-                                push group
-                                  start transform 1 0 -0 1 0 0
-                                    start clip glyph 159
-                                      start transform 1 0 0 1 0 0
-                                        solid 128 128 128 102
-                                      end transform
-                                    end clip
-                                  end transform
-                                pop group mode 3
-                              end clip
-                              push group
-                                start transform 1 0 -0 1 0 0
-                                  start clip glyph 159
-                                    start transform 1 0 0 1 0 0
-                                      solid 128 128 128 102
-                                    end transform
-                                  end clip
-                                end transform
-                              pop group mode 3
-                            end clip
-                            push group
-                              start transform 1 0 -0 1 0 0
-                                start clip glyph 159
-                                  start transform 1 0 0 1 0 0
-                                    solid 128 128 128 102
-                                  end transform
-                                end clip
-                              end transform
-                            pop group mode 3
-                          end clip
-                          push group
-                            start transform 1 0 -0 1 0 0
-                              start clip glyph 159
-                                start transform 1 0 0 1 0 0
-                                  solid 128 128 128 102
-                                end transform
-                              end clip
-                            end transform
-                          pop group mode 3
-                        end clip
-                        push group
-                          start transform 1 0 -0 1 0 0
-                            start clip glyph 159
-                              start transform 1 0 0 1 0 0
-                                solid 128 128 128 102
-                              end transform
-                            end clip
-                          end transform
-                        pop group mode 3
-                      end clip
-                      push group
-                        start transform 1 0 -0 1 0 0
-                          start clip glyph 159
-                            start transform 1 0 0 1 0 0
-                              solid 128 128 128 102
-                            end transform
-                          end clip
-                        end transform
-                      pop group mode 3
-                    end clip
-                    push group
-                      start transform 1 0 -0 1 0 0
-                        start clip glyph 159
-                          start transform 1 0 0 1 0 0
-                            solid 128 128 128 102
-                          end transform
-                        end clip
-                      end transform
-                    pop group mode 3
-                  end clip
-                  push group
-                    start transform 1 0 -0 1 0 0
-                      start clip glyph 159
-                        start transform 1 0 0 1 0 0
-                          solid 128 128 128 102
-                        end transform
-                      end clip
-                    end transform
-                  pop group mode 3
-                end clip
-                push group
-                  start transform 1 0 -0 1 0 0
-                    start clip glyph 159
-                      start transform 1 0 0 1 0 0
-                        solid 128 128 128 102
-                      end transform
-                    end clip
-                  end transform
-                pop group mode 3
-              end clip
-              push group
-                start transform 1 0 -0 1 0 0
-                  start clip glyph 159
-                    start transform 1 0 0 1 0 0
-                      solid 128 128 128 102
-                    end transform
-                  end clip
-                end transform
-              pop group mode 3
-            end clip
-            push group
-              start transform 1 0 -0 1 0 0
-                start clip glyph 159
-                  start transform 1 0 0 1 0 0
-                    solid 128 128 128 102
-                  end transform
-                end clip
-              end transform
-            pop group mode 3
-          end clip
-          push group
-            start transform 1 0 -0 1 0 0
-              start clip glyph 159
-                start transform 1 0 0 1 0 0
-                  solid 128 128 128 102
-                end transform
-              end clip
-            end transform
-          pop group mode 3
-        end clip
-        push group
-          start transform 1 0 -0 1 0 0
-            start clip glyph 159
-              start transform 1 0 0 1 0 0
-                solid 128 128 128 102
-              end transform
-            end clip
-          end transform
-        pop group mode 3
-      end clip
-      push group
-        start transform 1 0 -0 1 0 0
-          start clip glyph 159
-            start transform 1 0 0 1 0 0
-              solid 128 128 128 102
-            end transform
-          end clip
-        end transform
-      pop group mode 3
-    end clip
     push group
       start transform 1 0 -0 1 0 0
         start clip glyph 159
diff --git a/test/api/results/test-154 b/test/api/results/test-154
index 8b329cf..f108da8 100644
--- a/test/api/results/test-154
+++ b/test/api/results/test-154
@@ -1,10 +1,16 @@
-# random seed: R02S9ffd1e4fb7cd9c50371f61b259bb32b5
+# random seed: R02S46170a7a8abc3ad07d2b70fd08efc176
 # Start of hb tests
 # Start of paint tests
 # Start of ot tests
 start clip rectangle 0 500 500 1e+03
   start transform 1 0 0 1 0 0
+    start transform 1 0 -0 1 0 0
+      paint color glyph 164; acting as failed
+    end transform
     start clip rectangle 100 100 900 900
+      start transform 1 0 -0 1 0 0
+        paint color glyph 93; acting as failed
+      end transform
       start clip rectangle 0 0 1e+03 1e+03
         start transform 1 0 -0 1 0 0
           start clip glyph 2
diff --git a/test/api/results/testvf-154 b/test/api/results/testvf-154
index 6da136f..cd6e9b9 100644
--- a/test/api/results/testvf-154
+++ b/test/api/results/testvf-154
@@ -1,10 +1,16 @@
-# random seed: R02S2212d33e4705ca20b6475a83d116b9ab
+# random seed: R02Sd6c6e6b574cffce42448b4c7ec9ed3b1
 # Start of hb tests
 # Start of paint tests
 # Start of ot tests
 start clip rectangle 0 500 500 1e+03
   start transform 1 0 0 1 0 0
+    start transform 1 0 -0 1 0 0
+      paint color glyph 164; acting as failed
+    end transform
     start clip rectangle 100 100 900 900
+      start transform 1 0 -0 1 0 0
+        paint color glyph 93; acting as failed
+      end transform
       start clip rectangle 0 0 1e+03 1e+03
         start transform 1 0 -0 1 0 0
           start clip glyph 2
diff --git a/test/api/test-paint.c b/test/api/test-paint.c
index 13b71c5..810b7ac 100644
--- a/test/api/test-paint.c
+++ b/test/api/test-paint.c
@@ -97,6 +97,20 @@
   print (data, "end transform");
 }
 
+static hb_bool_t
+paint_color_glyph (hb_paint_funcs_t *funcs,
+                   void *paint_data,
+                   hb_codepoint_t glyph,
+                   hb_font_t *font,
+                   void *user_data)
+{
+  paint_data_t *data = paint_data;
+
+  print (data, "paint color glyph %u; acting as failed", glyph);
+
+  return FALSE;
+}
+
 static void
 push_clip_glyph (hb_paint_funcs_t *funcs,
                  void *paint_data,
@@ -286,6 +300,7 @@
 
     hb_paint_funcs_set_push_transform_func (funcs, push_transform, NULL, NULL);
     hb_paint_funcs_set_pop_transform_func (funcs, pop_transform, NULL, NULL);
+    hb_paint_funcs_set_color_glyph_func (funcs, paint_color_glyph, NULL, NULL);
     hb_paint_funcs_set_push_clip_glyph_func (funcs, push_clip_glyph, NULL, NULL);
     hb_paint_funcs_set_push_clip_rectangle_func (funcs, push_clip_rectangle, NULL, NULL);
     hb_paint_funcs_set_pop_clip_func (funcs, pop_clip, NULL, NULL);
@@ -389,7 +404,7 @@
 
   /* Run
    *
-   * GENERATE_DATA=1 G_TEST_SRCDIR=./test/api ./build/test/api/test-ot-color -p TESTCASE > test/api/results/OUTPUT
+   * GENERATE_DATA=1 G_TEST_SRCDIR=./test/api ./build/test/api/test-paint -p TESTCASE > test/api/results/OUTPUT
    *
    * to produce the expected results file.
    */
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6697168080338944 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6697168080338944
new file mode 100644
index 0000000..1859841
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6697168080338944
Binary files differ
diff --git a/test/shape/data/in-house/fonts/507637795ce4f2975593da54d12b46f76c7cc4cc.ttf b/test/shape/data/in-house/fonts/507637795ce4f2975593da54d12b46f76c7cc4cc.ttf
new file mode 100644
index 0000000..e25dcca
--- /dev/null
+++ b/test/shape/data/in-house/fonts/507637795ce4f2975593da54d12b46f76c7cc4cc.ttf
Binary files differ
diff --git a/test/shape/data/in-house/tests/arabic-stch.tests b/test/shape/data/in-house/tests/arabic-stch.tests
index 491b242..890d8bf 100644
--- a/test/shape/data/in-house/tests/arabic-stch.tests
+++ b/test/shape/data/in-house/tests/arabic-stch.tests
@@ -1 +1,3 @@
 ../fonts/d9b8bc10985f24796826c29f7ccba3d0ae11ec02.ttf;--no-glyph-names;U+0718,U+070F,U+0718,U+0718,U+002E;[1=4+168|3=3+502|3=2+502|4=1@-1004,0+0|5=1@-876,0+0|5=1@-799,0+0|5=1@-722,0+0|5=1@-645,0+0|4=1@-566,0+0|5=1@-438,0+0|5=1@-361,0+0|5=1@-284,0+0|5=1@-207,0+0|4=1@-128,0+0|3=0+502]
+../fonts/507637795ce4f2975593da54d12b46f76c7cc4cc.ttf;--direction=l;U+0891,U+0661,U+0662,U+0663,U+0664,U+066B;[piastre-ar.head=0+0|piastre-ar.repeat=0@644,0+0|piastre-ar.repeat=0@778,0+0|piastre-ar.repeat=0@897,0+0|piastre-ar.repeat=0@1016,0+0|piastre-ar.repeat=0@1135,0+0|piastre-ar.repeat=0@1254,0+0|piastre-ar.repeat=0@1373,0+0|piastre-ar.repeat=0@1492,0+0|piastre-ar.tail=0@1611,0+0|one-ar=1+449|two-ar=2+449|three-ar=3+449|four-ar=4+449|decimalseparator-ar=5+222]
+../fonts/507637795ce4f2975593da54d12b46f76c7cc4cc.ttf;--direction=l;U+0661,U+0662,U+0663,U+0891,U+0664,U+066B;[one-ar=0+449|two-ar=1+449|three-ar=2+449|piastre-ar.head=3@-192,0+0|piastre-ar.repeat=3@452,0+0|piastre-ar.tail=3@586,0+0|four-ar=4+449|decimalseparator-ar=5+222]
diff --git a/util/view-cairo.hh b/util/view-cairo.hh
index d737b85..c96003c 100644
--- a/util/view-cairo.hh
+++ b/util/view-cairo.hh
@@ -202,6 +202,8 @@
       cairo_restore (cr);
     }
 
+  // https://github.com/harfbuzz/harfbuzz/issues/4378
+#if CAIRO_VERSION >= 11705
     if (l.num_clusters)
       cairo_show_text_glyphs (cr,
 			      l.utf8, l.utf8_len,
@@ -209,6 +211,7 @@
 			      l.clusters, l.num_clusters,
 			      l.cluster_flags);
     else
+#endif
       cairo_show_glyphs (cr, l.glyphs, l.num_glyphs);
   }