mirror of
https://github.com/harfbuzz/harfbuzz.git
synced 2025-04-12 16:23:01 +00:00
Compare commits
728 commits
Author | SHA1 | Date | |
---|---|---|---|
|
efcb7d3de1 | ||
|
5afbd187b6 | ||
|
e6b5dba369 | ||
|
d3ccdcdd80 | ||
|
b33f2e26ee | ||
|
ab3235150d | ||
|
5f80cc1600 | ||
|
6b0124284b | ||
|
caa9cf2e85 | ||
|
c7f980907f | ||
|
b1a0a4c228 | ||
|
6dff699f3f | ||
|
6697cd833a | ||
|
2c4bc83244 | ||
|
e31721b5cf | ||
|
a9e2c8f3aa | ||
|
a3d626b4b9 | ||
|
b99382e292 | ||
|
ba4a92c53b | ||
|
8a1ba4d151 | ||
|
fb04a306fc | ||
|
b43901151f | ||
|
b106a9ef58 | ||
|
59771e5613 | ||
|
fd9903fc4e | ||
|
f09c4d6dd8 | ||
|
1f0559392d | ||
|
d8f00171d7 | ||
|
cc065cf2e5 | ||
|
c60067c675 | ||
|
8456c33ac3 | ||
|
1f1cbb64ee | ||
|
aa6a37de61 | ||
|
ba309a1826 | ||
|
58d7ab2d59 | ||
|
328509ef66 | ||
|
03f4230188 | ||
|
5a46872853 | ||
|
9718681c99 | ||
|
2b5ae9dec3 | ||
|
155e1e633b | ||
|
f73039422e | ||
|
5efdb884a5 | ||
|
8132a6607f | ||
|
b2179dcfcd | ||
|
a777a9c535 | ||
|
e332777763 | ||
|
740a103ba1 | ||
|
a530672f04 | ||
|
628a9ee28a | ||
|
fbda749bdb | ||
|
da5a9fb860 | ||
|
b01cea95e1 | ||
|
1db93d2f6d | ||
|
ee50fad676 | ||
|
db953a43d0 | ||
|
69fd949014 | ||
|
2834900d92 | ||
|
e4e4d66523 | ||
|
c523f9ac13 | ||
|
f69ecc9438 | ||
|
6acb2942e8 | ||
|
bee08cf290 | ||
|
a46b93208a | ||
|
3cf48234b9 | ||
|
112b599826 | ||
|
6c98519c7e | ||
|
0a5cc89e00 | ||
|
d9304b69e0 | ||
|
58170206a1 | ||
|
a24c40dfb4 | ||
|
d74606bbff | ||
|
2d8e5255f3 | ||
|
f57b43c980 | ||
|
52a4bea109 | ||
|
b53000403e | ||
|
7dcd69544b | ||
|
c42b6ea829 | ||
|
e5541a0b63 | ||
|
d65fa93440 | ||
|
00b4f86e5f | ||
|
267de2bb90 | ||
|
5194ec4758 | ||
|
fa737da022 | ||
|
54295ccf45 | ||
|
0fecd2ecc3 | ||
|
a637c08d5a | ||
|
866096d04a | ||
|
b6cbd6a0fc | ||
|
2f86ab8d47 | ||
|
9971d84ea7 | ||
|
bf3ce2cb6b | ||
|
90331b41ef | ||
|
3207575979 | ||
|
0457d3d734 | ||
|
9ddf3da71e | ||
|
43a7784922 | ||
|
13752124d7 | ||
|
623a7a4198 | ||
|
c44f1e71d7 | ||
|
1337912680 | ||
|
cc782b5427 | ||
|
7ba4e87934 | ||
|
089a9961ad | ||
|
a55305038c | ||
|
8994e91487 | ||
|
d515630f6b | ||
|
d30d7f6b2b | ||
|
9cae040bb4 | ||
|
810fbedf27 | ||
|
6cc9c01aaa | ||
|
e10d647a73 | ||
|
e404cf0860 | ||
|
e480d9de96 | ||
|
60fc8b4cbc | ||
|
062c3b4d80 | ||
|
2152ff779c | ||
|
18ab0f5522 | ||
|
c6c8dcdeca | ||
|
6f5b8d59c7 | ||
|
7da049ed42 | ||
|
da0c459dd4 | ||
|
37989fb4cd | ||
|
d3e4977c70 | ||
|
ef8c25ad9f | ||
|
bbf0c6e781 | ||
|
321c14c920 | ||
|
7f5fafec0d | ||
|
8864c264b9 | ||
|
3d0816c7c4 | ||
|
591f00a281 | ||
|
7ebe6b48b6 | ||
|
4d5348d660 | ||
|
bed2d3dd2b | ||
|
89ab5f2b21 | ||
|
48e7e5a008 | ||
|
9f83bbbe64 | ||
|
91fd40ac7c | ||
|
ca66c64655 | ||
|
a1e587b75a | ||
|
a5b00faaf8 | ||
|
d53cbeee41 | ||
|
7c368dabae | ||
|
674ce63021 | ||
|
4f5b31b7ea | ||
|
4cf4099f07 | ||
|
4954edb2b1 | ||
|
afa0549dff | ||
|
67314b205a | ||
|
c260550ae5 | ||
|
18ced8dbb1 | ||
|
17c875c309 | ||
|
ea08b04752 | ||
|
cb44134cbf | ||
|
ef95dc0e7f | ||
|
c39ac0e171 | ||
|
1358e38154 | ||
|
1dac21c177 | ||
|
22f81f70cb | ||
|
aad5780f53 | ||
|
83481d65d0 | ||
|
a588761198 | ||
|
1f6da390e0 | ||
|
449752c57c | ||
|
b808d1746d | ||
|
9d584c4d3d | ||
|
82d664519c | ||
|
7ba0368200 | ||
|
283ab21841 | ||
|
0752e5852b | ||
|
ae8b288db7 | ||
|
c50c0a39e5 | ||
|
b4fd777c23 | ||
|
5ebe36e1ac | ||
|
208ffb3f1f | ||
|
dda1d95af2 | ||
|
0d4053b11d | ||
|
7c90f446c2 | ||
|
d47a47e20b | ||
|
7ab42f9af3 | ||
|
9609f50bad | ||
|
9a80c0da84 | ||
|
ba6869848f | ||
|
7f10c0edfd | ||
|
bd5b8a1feb | ||
|
e4410a85fa | ||
|
a6f563247e | ||
|
93288a1ced | ||
|
a410a042c7 | ||
|
4d83b238ea | ||
|
59001aa952 | ||
|
3d3f241941 | ||
|
75643768de | ||
|
29c800bd8d | ||
|
192d264ae7 | ||
|
4d2a362f84 | ||
|
bed29d1cd3 | ||
|
e16a985798 | ||
|
851d3e33b5 | ||
|
2b5f244639 | ||
|
eec9108416 | ||
|
fea0c0df33 | ||
|
fe51e23738 | ||
|
188531b3ba | ||
|
d81d4dfbd3 | ||
|
614013940d | ||
|
190ad35f71 | ||
|
6cf308c857 | ||
|
1402ecfecf | ||
|
46a30fe390 | ||
|
bb3a55a61a | ||
|
0affe12785 | ||
|
83d3ffc5d1 | ||
|
0ae4b8f48e | ||
|
aa450db1f7 | ||
|
10256a9fc7 | ||
|
6c337ddc24 | ||
|
59c0deba8f | ||
|
7876aac4eb | ||
|
4901ecd66e | ||
|
589e78cec5 | ||
|
5c3f23c09c | ||
|
b114518310 | ||
|
eda33efc88 | ||
|
c141541159 | ||
|
2fd2f8e711 | ||
|
b690de572c | ||
|
9c63dcb3fe | ||
|
ba709a385e | ||
|
0849d3d8b6 | ||
|
8e1502cce8 | ||
|
2ed9c2826a | ||
|
48ce9c397e | ||
|
ea6a172f84 | ||
|
7599d097c9 | ||
|
7612ec44dc | ||
|
391cbed883 | ||
|
4cc66435f9 | ||
|
74c82b3a29 | ||
|
f0e260ad73 | ||
|
af6b6b4828 | ||
|
4f12035e5d | ||
|
e4b633deb8 | ||
|
8d62ad3b35 | ||
|
c226da8c35 | ||
|
f48d641483 | ||
|
018858b2ce | ||
|
2421efc17b | ||
|
3259f9f89a | ||
|
55743b239f | ||
|
9afdc7e1d2 | ||
|
1c7a1c7b04 | ||
|
ed558e5da4 | ||
|
45a724b90c | ||
|
f53befb6a0 | ||
|
b159f5c74e | ||
|
298a367ad3 | ||
|
24a23aca69 | ||
|
91bd6bf0df | ||
|
40ef946ec5 | ||
|
b205a7fbe8 | ||
|
c274ee7b3e | ||
|
f0b0d92ab5 | ||
|
201a0fe361 | ||
|
6e17bd374f | ||
|
7153e7814b | ||
|
8db34adc37 | ||
|
e0aee5815a | ||
|
c3bc5e4c68 | ||
|
6509414227 | ||
|
977e4f94e0 | ||
|
8ae92d0d83 | ||
|
51a5618c54 | ||
|
a388989af4 | ||
|
f7f9cd1296 | ||
|
e320109e5d | ||
|
f9ad7c37b1 | ||
|
0b139a81fe | ||
|
4fd4dbb896 | ||
|
475afee0b8 | ||
|
0eeb6ccb42 | ||
|
cfb962d73c | ||
|
9fa31d1ed2 | ||
|
852f66a418 | ||
|
c867bc976a | ||
|
a551736532 | ||
|
6a82561f00 | ||
|
cc0451c949 | ||
|
e2a24ce13a | ||
|
be90974de8 | ||
|
1d25de8316 | ||
|
e3dc86bb0f | ||
|
a189b0f772 | ||
|
ca14981262 | ||
|
12e31ab7e8 | ||
|
14c07dcfa7 | ||
|
b2f7f6db1a | ||
|
64dcece342 | ||
|
4107cceea1 | ||
|
c84b9dca24 | ||
|
e57e728532 | ||
|
686503e2e0 | ||
|
24ad0dd46b | ||
|
b3d48c2c1b | ||
|
4822cb7672 | ||
|
60ce16f221 | ||
|
34b9100c67 | ||
|
82e0ff6da0 | ||
|
1a8352cfdb | ||
|
59aee7f3e8 | ||
|
0349359ce6 | ||
|
38889c3ad6 | ||
|
472e65dd0f | ||
|
0ebcc66506 | ||
|
696b4a26a8 | ||
|
ad9c473759 | ||
|
630bc9b45d | ||
|
719dafdaad | ||
|
27bb37c5d0 | ||
|
b24a93c68e | ||
|
9a0802dbe5 | ||
|
ee34711d64 | ||
|
220a8b9496 | ||
|
7c248cccb5 | ||
|
3e137c8e8a | ||
|
cf1772a492 | ||
|
a37fb2fbf7 | ||
|
24f9fd46ce | ||
|
5b3bf25bb8 | ||
|
f16196a00e | ||
|
0d5795c0a5 | ||
|
aacc667e51 | ||
|
cdfbb7efb9 | ||
|
ee15f723fd | ||
|
9298b31046 | ||
|
286e832854 | ||
|
a520ee9503 | ||
|
d65fd65608 | ||
|
1a7b31f260 | ||
|
7272abc35e | ||
|
6a50badb57 | ||
|
4dc25e7066 | ||
|
f9aabf7062 | ||
|
38db0f4c12 | ||
|
6ccfadb911 | ||
|
422ffff15c | ||
|
bd2bf3536c | ||
|
a9a3fd33a2 | ||
|
0a991cc543 | ||
|
14e5a046c8 | ||
|
a95a500d3d | ||
|
8d8fe19099 | ||
|
08781f6f7d | ||
|
93f8cbf4fa | ||
|
6958064c7f | ||
|
000a0ad7a6 | ||
|
e6519fcb2b | ||
|
e1d395f4b5 | ||
|
db8d099d4d | ||
|
13849d4205 | ||
|
e9d5ecca1d | ||
|
d2b722803f | ||
|
41d722c3d2 | ||
|
9d6e24a1d2 | ||
|
c1ed463195 | ||
|
bd05b260af | ||
|
da4758e791 | ||
|
b3a293813a | ||
|
bda5b832b0 | ||
|
09d983258b | ||
|
d441b4cbc7 | ||
|
e92cd9f769 | ||
|
1e9d101ed7 | ||
|
c73b54bcca | ||
|
db93dbb286 | ||
|
9e5a767855 | ||
|
64716226d2 | ||
|
27fc376fe9 | ||
|
aacaa8bba3 | ||
|
2502d0b698 | ||
|
d0fef9a1fc | ||
|
ad3225c648 | ||
|
00360049e3 | ||
|
f6744c2c73 | ||
|
379688c566 | ||
|
344915c9ea | ||
|
b0a5920d1a | ||
|
7e4698abe2 | ||
|
471ac1cdc0 | ||
|
5f61ccf07d | ||
|
a0fbd25e10 | ||
|
c2f8066b2f | ||
|
b57d2a2050 | ||
|
d6f5cbdd8c | ||
|
64240602b4 | ||
|
7b8ae3d067 | ||
|
0f18838c69 | ||
|
a115228329 | ||
|
e5a01efd07 | ||
|
7b48aa37a7 | ||
|
792b9b9337 | ||
|
43d421d388 | ||
|
aa233ecedc | ||
|
402876d489 | ||
|
c38d518718 | ||
|
2449eb0882 | ||
|
6388ce2224 | ||
|
b861b54178 | ||
|
7146e5818f | ||
|
41b396c64b | ||
|
83e0944f0f | ||
|
02733deded | ||
|
45b2d28d04 | ||
|
d76a23a3f1 | ||
|
b1a9219ac5 | ||
|
54962b3fce | ||
|
4807a021a1 | ||
|
829d1eda16 | ||
|
a0d76c5b37 | ||
|
bdee8658c6 | ||
|
469502c99b | ||
|
fbb81e344b | ||
|
8d300049f5 | ||
|
05cfdb9105 | ||
|
0b2a0bac47 | ||
|
5bf81c3758 | ||
|
a2c7dc0669 | ||
|
f0a67e9948 | ||
|
d014efd03d | ||
|
759e1881e8 | ||
|
15fcfcb606 | ||
|
5e6da54166 | ||
|
8687f5c38e | ||
|
8e8a9f6f40 | ||
|
cbc205c2f0 | ||
|
b1c50eb938 | ||
|
f98c203e7a | ||
|
8ca9fe7617 | ||
|
e4fe8bf95e | ||
|
3c30562dc7 | ||
|
756668d35c | ||
|
6b2f859232 | ||
|
8ca892b0e2 | ||
|
d247c116fb | ||
|
d2ccf595bd | ||
|
41dcc493e5 | ||
|
57deae5fd4 | ||
|
dbad6cdfec | ||
|
3c02fcd0e8 | ||
|
4323c6643b | ||
|
7a912c4746 | ||
|
c2e92b6f7b | ||
|
5a03844914 | ||
|
2edab536bd | ||
|
18e9550579 | ||
|
9c0ac9aec4 | ||
|
8ee8e0a213 | ||
|
885eef8ea5 | ||
|
d8a774c011 | ||
|
f88fe4d403 | ||
|
1531be8a1d | ||
|
9305aae476 | ||
|
7518718671 | ||
|
62c320a2d6 | ||
|
0b62666ece | ||
|
bcbd1df3dd | ||
|
e77fb46335 | ||
|
780809fb0c | ||
|
9f8e7ebf24 | ||
|
ff76244ea6 | ||
|
dc048b7c88 | ||
|
4ec560dd02 | ||
|
c6972ac6dd | ||
|
ec4d4b01e8 | ||
|
c88e819965 | ||
|
d067f2b224 | ||
|
0a01fc558b | ||
|
ec6f99c5ea | ||
|
9e639e676a | ||
|
1e812e43b3 | ||
|
7791f50e3a | ||
|
aa268fc8ef | ||
|
6ae7ef0659 | ||
|
a83faa061c | ||
|
402f89cb79 | ||
|
5cf1fa3add | ||
|
2ecc68c12f | ||
|
6b9d9f7259 | ||
|
9d05b03f83 | ||
|
39ade99d47 | ||
|
79c991e143 | ||
|
50ea460b93 | ||
|
43ff0f73cc | ||
|
437ce95059 | ||
|
68b07475a7 | ||
|
5a12bf417b | ||
|
712a403bec | ||
|
fae9d2ab27 | ||
|
e8ddb4325b | ||
|
c3eac5c0f3 | ||
|
2a878b1b76 | ||
|
e9348cd76d | ||
|
27fa1c4229 | ||
|
080bd09db3 | ||
|
3f6da0a367 | ||
|
4bb7f61050 | ||
|
aabf8aadf8 | ||
|
52852c6cb6 | ||
|
77314a3be7 | ||
|
5c01d8298c | ||
|
bd66336d45 | ||
|
8fd718c9eb | ||
|
a68f458612 | ||
|
f7cb3a3c8e | ||
|
6c1f27faab | ||
|
514b28af3c | ||
|
55ca000b0e | ||
|
73f1c2ba43 | ||
|
ecb9e393f2 | ||
|
493bf07596 | ||
|
78b3234396 | ||
|
52ad51382a | ||
|
4e5358a288 | ||
|
e27e7f1c7d | ||
|
460a8225ba | ||
|
575e70b063 | ||
|
41e14f7029 | ||
|
b8b56c4a67 | ||
|
a356603061 | ||
|
9abaf193d3 | ||
|
fe8a3972dd | ||
|
abc468275b | ||
|
6506bd7e82 | ||
|
9fbc2d23b5 | ||
|
0ce90f60ab | ||
|
bf55e33287 | ||
|
8685653cc7 | ||
|
ad9fa13d23 | ||
|
cd45a7f531 | ||
|
44705c1acb | ||
|
cda4b56bfe | ||
|
e8bed99b16 | ||
|
1147c0e1ca | ||
|
ad0bcec378 | ||
|
0d70cfacb2 | ||
|
77a319daa6 | ||
|
fc8334d96b | ||
|
a20138dcfc | ||
|
f379505d4d | ||
|
123a0d68a1 | ||
|
462a54895b | ||
|
3985939842 | ||
|
597a934368 | ||
|
4a3329dafb | ||
|
4b035ae611 | ||
|
34a919b980 | ||
|
547027837e | ||
|
d9b1101de6 | ||
|
b5d2ec4f83 | ||
|
92af2e47fc | ||
|
3ce6b720ac | ||
|
aecc9110a3 | ||
|
a6d295fa1e | ||
|
6b035cd7b7 | ||
|
83e58980a6 | ||
|
91f4a67d5d | ||
|
43e82682c5 | ||
|
2c11c9db52 | ||
|
dedc05c220 | ||
|
9b4eaff867 | ||
|
3a699c3764 | ||
|
b5ad6de8d6 | ||
|
a2d9c29b08 | ||
|
b5a04a9600 | ||
|
e10e5c3764 | ||
|
865d75ef30 | ||
|
d72968efac | ||
|
4b1f655a83 | ||
|
1a39f8935e | ||
|
5b27f32876 | ||
|
d069e79016 | ||
|
dbc04d1c7d | ||
|
6e472748d7 | ||
|
024e9356eb | ||
|
3f57f76e99 | ||
|
c4932fa57a | ||
|
e054db4ae2 | ||
|
ea5a14f7bc | ||
|
87c62f4ebb | ||
|
bc2851b407 | ||
|
b9a4d148c9 | ||
|
f2e5955e1e | ||
|
166e630768 | ||
|
83e85d2ac1 | ||
|
156b77327e | ||
|
74bd99e40e | ||
|
7a65fdcabf | ||
|
c969c2dec0 | ||
|
d19e45a1f5 | ||
|
51c68eb29d | ||
|
f400d8b30c | ||
|
1705723d7e | ||
|
7871ee5b6c | ||
|
c6d2e9e855 | ||
|
afe1af8fa9 | ||
|
e801e484f1 | ||
|
1390da5d12 | ||
|
94a6cfba89 | ||
|
77b20cf7b9 | ||
|
0113c86a2f | ||
|
71accd5e14 | ||
|
9d754188c6 | ||
|
9439e1fdad | ||
|
6cac2a1ae0 | ||
|
395270e494 | ||
|
2a06b85d4e | ||
|
f28daba53c | ||
|
161b20f333 | ||
|
e806c9ae2a | ||
|
e1c934421a | ||
|
db6431f140 | ||
|
bed809bc6b | ||
|
26da19f6ea | ||
|
3ba4266daa | ||
|
f9b4706151 | ||
|
2abe54fc9c | ||
|
ad8e4a29b9 | ||
|
ca3cd48fa3 | ||
|
718542ef7a | ||
|
c544028700 | ||
|
958e2c5331 | ||
|
c4b572a24c | ||
|
50fe45f43c | ||
|
628b868f44 | ||
|
9c6b6998ef | ||
|
2a471ed125 | ||
|
e9134c8ce3 | ||
|
9efd17e225 | ||
|
17ddc84406 | ||
|
a62058eee8 | ||
|
3199d1c1f5 | ||
|
e0c6c98025 | ||
|
d1826ca626 | ||
|
d9628a5643 | ||
|
c81b1c43b1 | ||
|
ad0a5c93b5 | ||
|
7e3c96582f | ||
|
3ef8709829 | ||
|
75ce774bc3 | ||
|
532ed228e7 | ||
|
69e1c3c352 | ||
|
484e8d4997 | ||
|
8226f597ac | ||
|
64dbeaf0f4 | ||
|
d59d435ec6 | ||
|
cb781f53aa | ||
|
1a759886d9 | ||
|
527a209674 | ||
|
4be765c083 | ||
|
4a43373aec | ||
|
00541f1952 | ||
|
a0543453de | ||
|
7504c67fb7 | ||
|
9d149c5284 | ||
|
753093d60e | ||
|
6fe1441782 | ||
|
17a83b748e | ||
|
44b7ba51a3 | ||
|
13900ce40d | ||
|
ffe955b9f9 | ||
|
894fee6db3 | ||
|
4d3642c188 | ||
|
6fbd6bb34e | ||
|
6a7b4dcae6 | ||
|
84ffb7e477 | ||
|
54db2b2ed6 | ||
|
bb4d37b052 | ||
|
51d3489ca1 | ||
|
a037d3815f | ||
|
59e6a1c477 | ||
|
3c4cb472d1 | ||
|
fcbf14a0e5 | ||
|
6ca8852eff | ||
|
0cd98ebbf7 | ||
|
41626401b0 | ||
|
aaf5c06d62 | ||
|
40c77a1c5a | ||
|
81339256da | ||
|
87830b62c6 | ||
|
7614320a13 | ||
|
882d328839 | ||
|
ffee85d67f | ||
|
dcb80ecbd9 | ||
|
23937e8cd5 | ||
|
9b451f2055 | ||
|
7222c1e50f | ||
|
e450552d07 | ||
|
b12612f525 | ||
|
8280ef7d93 | ||
|
ea1434b897 | ||
|
aaecaa4c0e | ||
|
f71faf5fec | ||
|
e76b689fe1 | ||
|
827be1b23c | ||
|
13d98f1ded | ||
|
9a0cf8d641 | ||
|
084fb3ab4f | ||
|
51d8ef48d9 | ||
|
47124e6337 | ||
|
d5d199fbc7 | ||
|
2c5ab14aaa | ||
|
a058a1f223 | ||
|
13ee8edf06 | ||
|
46485124ea | ||
|
6fe550306c | ||
|
97a5c52af4 | ||
|
6938ee0342 | ||
|
74bb7c52f3 | ||
|
081fcbdf5a | ||
|
0a1b26b862 | ||
|
76c3beaf36 | ||
|
2099db378a | ||
|
043980a60e | ||
|
474c6e43a6 | ||
|
22e5469cec | ||
|
5f23b9767a | ||
|
1ba907209f | ||
|
e41dc20c1c |
898 changed files with 15275 additions and 9898 deletions
48
.ci/build-win.sh
Executable file
48
.ci/build-win.sh
Executable file
|
@ -0,0 +1,48 @@
|
|||
#!/bin/bash
|
||||
set -ex
|
||||
|
||||
if [ "$#" -lt 1 ]
|
||||
then
|
||||
echo "Usage $0 ARCH (ARCH can be 32 or 64)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ARCH=$1
|
||||
shift
|
||||
|
||||
BUILD=build-win${ARCH}
|
||||
INSTALL=install-win${ARCH}
|
||||
DIST=harfbuzz-win${ARCH}
|
||||
|
||||
meson setup \
|
||||
--buildtype=release \
|
||||
--prefix="${PWD}/${BUILD}/${INSTALL}" \
|
||||
--cross-file=.ci/win${ARCH}-cross-file.txt \
|
||||
--wrap-mode=default \
|
||||
--strip \
|
||||
-Dtests=enabled \
|
||||
-Dcairo=enabled \
|
||||
-Dcairo:fontconfig=disabled \
|
||||
-Dcairo:freetype=disabled \
|
||||
-Dcairo:dwrite=disabled \
|
||||
-Dcairo:tests=disabled \
|
||||
-Dglib=enabled \
|
||||
-Dlibffi:tests=false \
|
||||
-Dfreetype=disabled \
|
||||
-Dicu=disabled \
|
||||
-Dchafa=disabled \
|
||||
-Dgdi=enabled \
|
||||
-Ddirectwrite=enabled \
|
||||
${BUILD} \
|
||||
"$@"
|
||||
|
||||
# building with all the cores won't work fine with CricleCI for some reason
|
||||
meson compile -C ${BUILD} -j3
|
||||
meson install -C ${BUILD}
|
||||
|
||||
mkdir ${BUILD}/${DIST}
|
||||
cp ${BUILD}/${INSTALL}/bin/hb-*.exe ${BUILD}/${DIST}
|
||||
cp ${BUILD}/${INSTALL}/bin/*.dll ${BUILD}/${DIST}
|
||||
rm -f ${DIST}.zip
|
||||
(cd ${BUILD} && zip -r ../${DIST}.zip ${DIST})
|
||||
echo "${DIST}.zip is ready."
|
|
@ -1,28 +0,0 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
meson --cross-file=.ci/win32-cross-file.txt \
|
||||
--wrap-mode=default \
|
||||
-Dtests=disabled \
|
||||
-Dcairo=enabled \
|
||||
-Dcairo:fontconfig=disabled \
|
||||
-Dcairo:freetype=disabled \
|
||||
-Dcairo:dwrite=disabled \
|
||||
-Dcairo:tests=disabled \
|
||||
-Dglib=enabled \
|
||||
-Dfreetype=disabled \
|
||||
-Dgdi=enabled \
|
||||
-Ddirectwrite=enabled \
|
||||
win32build \
|
||||
$@
|
||||
|
||||
ninja -Cwin32build -j3 # building with all the cores won't work fine with CricleCI for some reason
|
||||
|
||||
rm -rf win32build/harfbuzz-win32
|
||||
mkdir win32build/harfbuzz-win32
|
||||
cp win32build/util/hb-*.exe win32build/harfbuzz-win32
|
||||
find win32build -name '*.dll' -exec cp {} win32build/harfbuzz-win32 \;
|
||||
i686-w64-mingw32-strip win32build/harfbuzz-win32/*.{dll,exe}
|
||||
rm -f harfbuzz-win32.zip
|
||||
(cd win32build && zip -r ../harfbuzz-win32.zip harfbuzz-win32)
|
||||
echo "harfbuzz-win32.zip is ready."
|
|
@ -1,28 +0,0 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
meson --cross-file=.ci/win64-cross-file.txt \
|
||||
--wrap-mode=default \
|
||||
-Dtests=disabled \
|
||||
-Dcairo=enabled \
|
||||
-Dcairo:fontconfig=disabled \
|
||||
-Dcairo:freetype=disabled \
|
||||
-Dcairo:dwrite=disabled \
|
||||
-Dcairo:tests=disabled \
|
||||
-Dglib=enabled \
|
||||
-Dfreetype=disabled \
|
||||
-Dgdi=enabled \
|
||||
-Ddirectwrite=enabled \
|
||||
win64build \
|
||||
$@
|
||||
|
||||
ninja -Cwin64build -j3 # building with all the cores won't work fine with CricleCI for some reason
|
||||
|
||||
rm -rf win64build/harfbuzz-win64
|
||||
mkdir win64build/harfbuzz-win64
|
||||
cp win64build/util/hb-*.exe win64build/harfbuzz-win64
|
||||
find win64build -name '*.dll' -exec cp {} win64build/harfbuzz-win64 \;
|
||||
x86_64-w64-mingw32-strip win64build/harfbuzz-win64/*.{dll,exe}
|
||||
rm -f harfbuzz-win64.zip
|
||||
(cd win64build && zip -r ../harfbuzz-win64.zip harfbuzz-win64)
|
||||
echo "harfbuzz-win64.zip is ready."
|
|
@ -11,12 +11,11 @@ fi
|
|||
if ! hash ghr 2> /dev/null; then
|
||||
_GHR_VER=v0.14.0
|
||||
_GHR=ghr_${_GHR_VER}_linux_amd64
|
||||
mkdir -p $HOME/.local/bin
|
||||
curl -sfL https://github.com/tcnksm/ghr/releases/download/$_GHR_VER/$_GHR.tar.gz |
|
||||
tar xz -C $HOME/.local/bin --strip-components=1 $_GHR/ghr
|
||||
tar xz -C . --strip-components=1 $_GHR/ghr
|
||||
fi
|
||||
|
||||
ghr -replace \
|
||||
./ghr -replace \
|
||||
-u $CIRCLE_PROJECT_USERNAME \
|
||||
-r $CIRCLE_PROJECT_REPONAME \
|
||||
$CIRCLE_TAG \
|
||||
|
|
|
@ -4,55 +4,55 @@
|
|||
#
|
||||
# pip-compile --generate-hashes .ci/requirements-fonttools.in
|
||||
#
|
||||
fonttools==4.56.0 \
|
||||
--hash=sha256:003548eadd674175510773f73fb2060bb46adb77c94854af3e0cc5bc70260049 \
|
||||
--hash=sha256:0073b62c3438cf0058488c002ea90489e8801d3a7af5ce5f7c05c105bee815c3 \
|
||||
--hash=sha256:1088182f68c303b50ca4dc0c82d42083d176cba37af1937e1a976a31149d4d14 \
|
||||
--hash=sha256:133bedb9a5c6376ad43e6518b7e2cd2f866a05b1998f14842631d5feb36b5786 \
|
||||
--hash=sha256:14a3e3e6b211660db54ca1ef7006401e4a694e53ffd4553ab9bc87ead01d0f05 \
|
||||
--hash=sha256:17f39313b649037f6c800209984a11fc256a6137cbe5487091c6c7187cae4685 \
|
||||
--hash=sha256:193b86e9f769320bc98ffdb42accafb5d0c8c49bd62884f1c0702bc598b3f0a2 \
|
||||
--hash=sha256:2d351275f73ebdd81dd5b09a8b8dac7a30f29a279d41e1c1192aedf1b6dced40 \
|
||||
--hash=sha256:300c310bb725b2bdb4f5fc7e148e190bd69f01925c7ab437b9c0ca3e1c7cd9ba \
|
||||
--hash=sha256:331954d002dbf5e704c7f3756028e21db07097c19722569983ba4d74df014000 \
|
||||
--hash=sha256:38b947de71748bab150259ee05a775e8a0635891568e9fdb3cdd7d0e0004e62f \
|
||||
--hash=sha256:3cf4f8d2a30b454ac682e12c61831dcb174950c406011418e739de592bbf8f76 \
|
||||
--hash=sha256:3fd3fccb7b9adaaecfa79ad51b759f2123e1aba97f857936ce044d4f029abd71 \
|
||||
--hash=sha256:442ad4122468d0e47d83bc59d0e91b474593a8c813839e1872e47c7a0cb53b10 \
|
||||
--hash=sha256:47b5e4680002ae1756d3ae3b6114e20aaee6cc5c69d1e5911f5ffffd3ee46c6b \
|
||||
--hash=sha256:53f5e9767978a4daf46f28e09dbeb7d010319924ae622f7b56174b777258e5ba \
|
||||
--hash=sha256:62b4c6802fa28e14dba010e75190e0e6228513573f1eeae57b11aa1a39b7e5b1 \
|
||||
--hash=sha256:62cc1253827d1e500fde9dbe981219fea4eb000fd63402283472d38e7d8aa1c6 \
|
||||
--hash=sha256:654ac4583e2d7c62aebc6fc6a4c6736f078f50300e18aa105d87ce8925cfac31 \
|
||||
--hash=sha256:661a8995d11e6e4914a44ca7d52d1286e2d9b154f685a4d1f69add8418961563 \
|
||||
--hash=sha256:6c1d38642ca2dddc7ae992ef5d026e5061a84f10ff2b906be5680ab089f55bb8 \
|
||||
--hash=sha256:6e81c1cc80c1d8bf071356cc3e0e25071fbba1c75afc48d41b26048980b3c771 \
|
||||
--hash=sha256:705837eae384fe21cee5e5746fd4f4b2f06f87544fa60f60740007e0aa600311 \
|
||||
--hash=sha256:7ef04bc7827adb7532be3d14462390dd71287644516af3f1e67f1e6ff9c6d6df \
|
||||
--hash=sha256:86b2a1013ef7a64d2e94606632683f07712045ed86d937c11ef4dde97319c086 \
|
||||
--hash=sha256:8d1613abd5af2f93c05867b3a3759a56e8bf97eb79b1da76b2bc10892f96ff16 \
|
||||
--hash=sha256:965d0209e6dbdb9416100123b6709cb13f5232e2d52d17ed37f9df0cc31e2b35 \
|
||||
--hash=sha256:96a4271f63a615bcb902b9f56de00ea225d6896052c49f20d0c91e9f43529a29 \
|
||||
--hash=sha256:9d94449ad0a5f2a8bf5d2f8d71d65088aee48adbe45f3c5f8e00e3ad861ed81a \
|
||||
--hash=sha256:9da650cb29bc098b8cfd15ef09009c914b35c7986c8fa9f08b51108b7bc393b4 \
|
||||
--hash=sha256:a05d1f07eb0a7d755fbe01fee1fd255c3a4d3730130cf1bfefb682d18fd2fcea \
|
||||
--hash=sha256:a114d1567e1a1586b7e9e7fc2ff686ca542a82769a296cef131e4c4af51e58f4 \
|
||||
--hash=sha256:a1af375734018951c31c0737d04a9d5fd0a353a0253db5fbed2ccd44eac62d8c \
|
||||
--hash=sha256:b23d30a2c0b992fb1c4f8ac9bfde44b5586d23457759b6cf9a787f1a35179ee0 \
|
||||
--hash=sha256:bc871904a53a9d4d908673c6faa15689874af1c7c5ac403a8e12d967ebd0c0dc \
|
||||
--hash=sha256:bce60f9a977c9d3d51de475af3f3581d9b36952e1f8fc19a1f2254f1dda7ce9c \
|
||||
--hash=sha256:bd9825822e7bb243f285013e653f6741954d8147427aaa0324a862cdbf4cbf62 \
|
||||
--hash=sha256:ca7962e8e5fc047cc4e59389959843aafbf7445b6c08c20d883e60ced46370a5 \
|
||||
--hash=sha256:d0cb73ccf7f6d7ca8d0bc7ea8ac0a5b84969a41c56ac3ac3422a24df2680546f \
|
||||
--hash=sha256:d54a45d30251f1d729e69e5b675f9a08b7da413391a1227781e2a297fa37f6d2 \
|
||||
--hash=sha256:d6ca96d1b61a707ba01a43318c9c40aaf11a5a568d1e61146fafa6ab20890793 \
|
||||
--hash=sha256:d6f195c14c01bd057bc9b4f70756b510e009c83c5ea67b25ced3e2c38e6ee6e9 \
|
||||
--hash=sha256:e2cad98c94833465bcf28f51c248aaf07ca022efc6a3eba750ad9c1e0256d278 \
|
||||
--hash=sha256:e2e993e8db36306cc3f1734edc8ea67906c55f98683d6fd34c3fc5593fdbba4c \
|
||||
--hash=sha256:e9270505a19361e81eecdbc2c251ad1e1a9a9c2ad75fa022ccdee533f55535dc \
|
||||
--hash=sha256:f20e2c0dfab82983a90f3d00703ac0960412036153e5023eed2b4641d7d5e692 \
|
||||
--hash=sha256:f36a0868f47b7566237640c026c65a86d09a3d9ca5df1cd039e30a1da73098a0 \
|
||||
--hash=sha256:f59746f7953f69cc3290ce2f971ab01056e55ddd0fb8b792c31a8acd7fee2d28 \
|
||||
--hash=sha256:fa760e5fe8b50cbc2d71884a1eff2ed2b95a005f02dda2fa431560db0ddd927f \
|
||||
--hash=sha256:ffda9b8cd9cb8b301cae2602ec62375b59e2e2108a117746f12215145e3f786c
|
||||
fonttools==4.57.0 \
|
||||
--hash=sha256:03290e818782e7edb159474144fca11e36a8ed6663d1fcbd5268eb550594fd8e \
|
||||
--hash=sha256:0425c2e052a5f1516c94e5855dbda706ae5a768631e9fcc34e57d074d1b65b92 \
|
||||
--hash=sha256:05efceb2cb5f6ec92a4180fcb7a64aa8d3385fd49cfbbe459350229d1974f0b1 \
|
||||
--hash=sha256:17168a4670bbe3775f3f3f72d23ee786bd965395381dfbb70111e25e81505b9d \
|
||||
--hash=sha256:3122c604a675513c68bd24c6a8f9091f1c2376d18e8f5fe5a101746c81b3e98f \
|
||||
--hash=sha256:34687a5d21f1d688d7d8d416cb4c5b9c87fca8a1797ec0d74b9fdebfa55c09ab \
|
||||
--hash=sha256:3871349303bdec958360eedb619169a779956503ffb4543bb3e6211e09b647c4 \
|
||||
--hash=sha256:39acf68abdfc74e19de7485f8f7396fa4d2418efea239b7061d6ed6a2510c746 \
|
||||
--hash=sha256:3cf97236b192a50a4bf200dc5ba405aa78d4f537a2c6e4c624bb60466d5b03bd \
|
||||
--hash=sha256:408ce299696012d503b714778d89aa476f032414ae57e57b42e4b92363e0b8ef \
|
||||
--hash=sha256:44c26a311be2ac130f40a96769264809d3b0cb297518669db437d1cc82974888 \
|
||||
--hash=sha256:46370ac47a1e91895d40e9ad48effbe8e9d9db1a4b80888095bc00e7beaa042f \
|
||||
--hash=sha256:4dea5893b58d4637ffa925536462ba626f8a1b9ffbe2f5c272cdf2c6ebadb817 \
|
||||
--hash=sha256:51d8482e96b28fb28aa8e50b5706f3cee06de85cbe2dce80dbd1917ae22ec5a6 \
|
||||
--hash=sha256:541cb48191a19ceb1a2a4b90c1fcebd22a1ff7491010d3cf840dd3a68aebd654 \
|
||||
--hash=sha256:579ba873d7f2a96f78b2e11028f7472146ae181cae0e4d814a37a09e93d5c5cc \
|
||||
--hash=sha256:57e30241524879ea10cdf79c737037221f77cc126a8cdc8ff2c94d4a522504b9 \
|
||||
--hash=sha256:69ab81b66ebaa8d430ba56c7a5f9abe0183afefd3a2d6e483060343398b13fb1 \
|
||||
--hash=sha256:6e3e1ec10c29bae0ea826b61f265ec5c858c5ba2ce2e69a71a62f285cf8e4595 \
|
||||
--hash=sha256:727ece10e065be2f9dd239d15dd5d60a66e17eac11aea47d447f9f03fdbc42de \
|
||||
--hash=sha256:7339e6a3283e4b0ade99cade51e97cde3d54cd6d1c3744459e886b66d630c8b3 \
|
||||
--hash=sha256:767604f244dc17c68d3e2dbf98e038d11a18abc078f2d0f84b6c24571d9c0b13 \
|
||||
--hash=sha256:7a64edd3ff6a7f711a15bd70b4458611fb240176ec11ad8845ccbab4fe6745db \
|
||||
--hash=sha256:81aa97669cd726349eb7bd43ca540cf418b279ee3caba5e2e295fb4e8f841c02 \
|
||||
--hash=sha256:84c41ba992df5b8d680b89fd84c6a1f2aca2b9f1ae8a67400c8930cd4ea115f6 \
|
||||
--hash=sha256:84fd56c78d431606332a0627c16e2a63d243d0d8b05521257d77c6529abe14d8 \
|
||||
--hash=sha256:889e45e976c74abc7256d3064aa7c1295aa283c6bb19810b9f8b604dfe5c7f31 \
|
||||
--hash=sha256:8e2e12d0d862f43d51e5afb8b9751c77e6bec7d2dc00aad80641364e9df5b199 \
|
||||
--hash=sha256:967b65232e104f4b0f6370a62eb33089e00024f2ce143aecbf9755649421c683 \
|
||||
--hash=sha256:9d077f909f2343daf4495ba22bb0e23b62886e8ec7c109ee8234bdbd678cf344 \
|
||||
--hash=sha256:9d57b4e23ebbe985125d3f0cabbf286efa191ab60bbadb9326091050d88e8213 \
|
||||
--hash=sha256:a1968f2a2003c97c4ce6308dc2498d5fd4364ad309900930aa5a503c9851aec8 \
|
||||
--hash=sha256:a2a722c0e4bfd9966a11ff55c895c817158fcce1b2b6700205a376403b546ad9 \
|
||||
--hash=sha256:a97bb05eb24637714a04dee85bdf0ad1941df64fe3b802ee4ac1c284a5f97b7c \
|
||||
--hash=sha256:aff40f8ac6763d05c2c8f6d240c6dac4bb92640a86d9b0c3f3fff4404f34095c \
|
||||
--hash=sha256:babe8d1eb059a53e560e7bf29f8e8f4accc8b6cfb9b5fd10e485bde77e71ef41 \
|
||||
--hash=sha256:bbceffc80aa02d9e8b99f2a7491ed8c4a783b2fc4020119dc405ca14fb5c758c \
|
||||
--hash=sha256:c59375e85126b15a90fcba3443eaac58f3073ba091f02410eaa286da9ad80ed8 \
|
||||
--hash=sha256:ca2aed95855506b7ae94e8f1f6217b7673c929e4f4f1217bcaa236253055cb36 \
|
||||
--hash=sha256:cc066cb98b912f525ae901a24cd381a656f024f76203bc85f78fcc9e66ae5aec \
|
||||
--hash=sha256:cdef9a056c222d0479a1fdb721430f9efd68268014c54e8166133d2643cb05d9 \
|
||||
--hash=sha256:d07f1b64008e39fceae7aa99e38df8385d7d24a474a8c9872645c4397b674481 \
|
||||
--hash=sha256:d639397de852f2ccfb3134b152c741406752640a266d9c1365b0f23d7b88077f \
|
||||
--hash=sha256:dff02c5c8423a657c550b48231d0a48d7e2b2e131088e55983cfe74ccc2c7cc9 \
|
||||
--hash=sha256:e952c684274a7714b3160f57ec1d78309f955c6335c04433f07d36c5eb27b1f9 \
|
||||
--hash=sha256:ea1e9e43ca56b0c12440a7c689b1350066595bebcaa83baad05b8b2675129d98 \
|
||||
--hash=sha256:f022601f3ee9e1f6658ed6d184ce27fa5216cee5b82d279e0f0bde5deebece72 \
|
||||
--hash=sha256:f0e9618630edd1910ad4f07f60d77c184b2f572c8ee43305ea3265675cbbfe7e \
|
||||
--hash=sha256:f1d6bc9c23356908db712d282acb3eebd4ae5ec6d8b696aa40342b1d84f8e9e3 \
|
||||
--hash=sha256:f4376819c1c778d59e0a31db5dc6ede854e9edf28bbfa5b756604727f7f800ac
|
||||
# via -r requirements-fonttools.in
|
||||
|
|
|
@ -4,146 +4,84 @@
|
|||
#
|
||||
# pip-compile --allow-unsafe --generate-hashes --output-file=.ci/requirements.txt .ci/requirements.in
|
||||
#
|
||||
fonttools==4.56.0 \
|
||||
--hash=sha256:003548eadd674175510773f73fb2060bb46adb77c94854af3e0cc5bc70260049 \
|
||||
--hash=sha256:0073b62c3438cf0058488c002ea90489e8801d3a7af5ce5f7c05c105bee815c3 \
|
||||
--hash=sha256:1088182f68c303b50ca4dc0c82d42083d176cba37af1937e1a976a31149d4d14 \
|
||||
--hash=sha256:133bedb9a5c6376ad43e6518b7e2cd2f866a05b1998f14842631d5feb36b5786 \
|
||||
--hash=sha256:14a3e3e6b211660db54ca1ef7006401e4a694e53ffd4553ab9bc87ead01d0f05 \
|
||||
--hash=sha256:17f39313b649037f6c800209984a11fc256a6137cbe5487091c6c7187cae4685 \
|
||||
--hash=sha256:193b86e9f769320bc98ffdb42accafb5d0c8c49bd62884f1c0702bc598b3f0a2 \
|
||||
--hash=sha256:2d351275f73ebdd81dd5b09a8b8dac7a30f29a279d41e1c1192aedf1b6dced40 \
|
||||
--hash=sha256:300c310bb725b2bdb4f5fc7e148e190bd69f01925c7ab437b9c0ca3e1c7cd9ba \
|
||||
--hash=sha256:331954d002dbf5e704c7f3756028e21db07097c19722569983ba4d74df014000 \
|
||||
--hash=sha256:38b947de71748bab150259ee05a775e8a0635891568e9fdb3cdd7d0e0004e62f \
|
||||
--hash=sha256:3cf4f8d2a30b454ac682e12c61831dcb174950c406011418e739de592bbf8f76 \
|
||||
--hash=sha256:3fd3fccb7b9adaaecfa79ad51b759f2123e1aba97f857936ce044d4f029abd71 \
|
||||
--hash=sha256:442ad4122468d0e47d83bc59d0e91b474593a8c813839e1872e47c7a0cb53b10 \
|
||||
--hash=sha256:47b5e4680002ae1756d3ae3b6114e20aaee6cc5c69d1e5911f5ffffd3ee46c6b \
|
||||
--hash=sha256:53f5e9767978a4daf46f28e09dbeb7d010319924ae622f7b56174b777258e5ba \
|
||||
--hash=sha256:62b4c6802fa28e14dba010e75190e0e6228513573f1eeae57b11aa1a39b7e5b1 \
|
||||
--hash=sha256:62cc1253827d1e500fde9dbe981219fea4eb000fd63402283472d38e7d8aa1c6 \
|
||||
--hash=sha256:654ac4583e2d7c62aebc6fc6a4c6736f078f50300e18aa105d87ce8925cfac31 \
|
||||
--hash=sha256:661a8995d11e6e4914a44ca7d52d1286e2d9b154f685a4d1f69add8418961563 \
|
||||
--hash=sha256:6c1d38642ca2dddc7ae992ef5d026e5061a84f10ff2b906be5680ab089f55bb8 \
|
||||
--hash=sha256:6e81c1cc80c1d8bf071356cc3e0e25071fbba1c75afc48d41b26048980b3c771 \
|
||||
--hash=sha256:705837eae384fe21cee5e5746fd4f4b2f06f87544fa60f60740007e0aa600311 \
|
||||
--hash=sha256:7ef04bc7827adb7532be3d14462390dd71287644516af3f1e67f1e6ff9c6d6df \
|
||||
--hash=sha256:86b2a1013ef7a64d2e94606632683f07712045ed86d937c11ef4dde97319c086 \
|
||||
--hash=sha256:8d1613abd5af2f93c05867b3a3759a56e8bf97eb79b1da76b2bc10892f96ff16 \
|
||||
--hash=sha256:965d0209e6dbdb9416100123b6709cb13f5232e2d52d17ed37f9df0cc31e2b35 \
|
||||
--hash=sha256:96a4271f63a615bcb902b9f56de00ea225d6896052c49f20d0c91e9f43529a29 \
|
||||
--hash=sha256:9d94449ad0a5f2a8bf5d2f8d71d65088aee48adbe45f3c5f8e00e3ad861ed81a \
|
||||
--hash=sha256:9da650cb29bc098b8cfd15ef09009c914b35c7986c8fa9f08b51108b7bc393b4 \
|
||||
--hash=sha256:a05d1f07eb0a7d755fbe01fee1fd255c3a4d3730130cf1bfefb682d18fd2fcea \
|
||||
--hash=sha256:a114d1567e1a1586b7e9e7fc2ff686ca542a82769a296cef131e4c4af51e58f4 \
|
||||
--hash=sha256:a1af375734018951c31c0737d04a9d5fd0a353a0253db5fbed2ccd44eac62d8c \
|
||||
--hash=sha256:b23d30a2c0b992fb1c4f8ac9bfde44b5586d23457759b6cf9a787f1a35179ee0 \
|
||||
--hash=sha256:bc871904a53a9d4d908673c6faa15689874af1c7c5ac403a8e12d967ebd0c0dc \
|
||||
--hash=sha256:bce60f9a977c9d3d51de475af3f3581d9b36952e1f8fc19a1f2254f1dda7ce9c \
|
||||
--hash=sha256:bd9825822e7bb243f285013e653f6741954d8147427aaa0324a862cdbf4cbf62 \
|
||||
--hash=sha256:ca7962e8e5fc047cc4e59389959843aafbf7445b6c08c20d883e60ced46370a5 \
|
||||
--hash=sha256:d0cb73ccf7f6d7ca8d0bc7ea8ac0a5b84969a41c56ac3ac3422a24df2680546f \
|
||||
--hash=sha256:d54a45d30251f1d729e69e5b675f9a08b7da413391a1227781e2a297fa37f6d2 \
|
||||
--hash=sha256:d6ca96d1b61a707ba01a43318c9c40aaf11a5a568d1e61146fafa6ab20890793 \
|
||||
--hash=sha256:d6f195c14c01bd057bc9b4f70756b510e009c83c5ea67b25ced3e2c38e6ee6e9 \
|
||||
--hash=sha256:e2cad98c94833465bcf28f51c248aaf07ca022efc6a3eba750ad9c1e0256d278 \
|
||||
--hash=sha256:e2e993e8db36306cc3f1734edc8ea67906c55f98683d6fd34c3fc5593fdbba4c \
|
||||
--hash=sha256:e9270505a19361e81eecdbc2c251ad1e1a9a9c2ad75fa022ccdee533f55535dc \
|
||||
--hash=sha256:f20e2c0dfab82983a90f3d00703ac0960412036153e5023eed2b4641d7d5e692 \
|
||||
--hash=sha256:f36a0868f47b7566237640c026c65a86d09a3d9ca5df1cd039e30a1da73098a0 \
|
||||
--hash=sha256:f59746f7953f69cc3290ce2f971ab01056e55ddd0fb8b792c31a8acd7fee2d28 \
|
||||
--hash=sha256:fa760e5fe8b50cbc2d71884a1eff2ed2b95a005f02dda2fa431560db0ddd927f \
|
||||
--hash=sha256:ffda9b8cd9cb8b301cae2602ec62375b59e2e2108a117746f12215145e3f786c
|
||||
fonttools==4.57.0 \
|
||||
--hash=sha256:03290e818782e7edb159474144fca11e36a8ed6663d1fcbd5268eb550594fd8e \
|
||||
--hash=sha256:0425c2e052a5f1516c94e5855dbda706ae5a768631e9fcc34e57d074d1b65b92 \
|
||||
--hash=sha256:05efceb2cb5f6ec92a4180fcb7a64aa8d3385fd49cfbbe459350229d1974f0b1 \
|
||||
--hash=sha256:17168a4670bbe3775f3f3f72d23ee786bd965395381dfbb70111e25e81505b9d \
|
||||
--hash=sha256:3122c604a675513c68bd24c6a8f9091f1c2376d18e8f5fe5a101746c81b3e98f \
|
||||
--hash=sha256:34687a5d21f1d688d7d8d416cb4c5b9c87fca8a1797ec0d74b9fdebfa55c09ab \
|
||||
--hash=sha256:3871349303bdec958360eedb619169a779956503ffb4543bb3e6211e09b647c4 \
|
||||
--hash=sha256:39acf68abdfc74e19de7485f8f7396fa4d2418efea239b7061d6ed6a2510c746 \
|
||||
--hash=sha256:3cf97236b192a50a4bf200dc5ba405aa78d4f537a2c6e4c624bb60466d5b03bd \
|
||||
--hash=sha256:408ce299696012d503b714778d89aa476f032414ae57e57b42e4b92363e0b8ef \
|
||||
--hash=sha256:44c26a311be2ac130f40a96769264809d3b0cb297518669db437d1cc82974888 \
|
||||
--hash=sha256:46370ac47a1e91895d40e9ad48effbe8e9d9db1a4b80888095bc00e7beaa042f \
|
||||
--hash=sha256:4dea5893b58d4637ffa925536462ba626f8a1b9ffbe2f5c272cdf2c6ebadb817 \
|
||||
--hash=sha256:51d8482e96b28fb28aa8e50b5706f3cee06de85cbe2dce80dbd1917ae22ec5a6 \
|
||||
--hash=sha256:541cb48191a19ceb1a2a4b90c1fcebd22a1ff7491010d3cf840dd3a68aebd654 \
|
||||
--hash=sha256:579ba873d7f2a96f78b2e11028f7472146ae181cae0e4d814a37a09e93d5c5cc \
|
||||
--hash=sha256:57e30241524879ea10cdf79c737037221f77cc126a8cdc8ff2c94d4a522504b9 \
|
||||
--hash=sha256:69ab81b66ebaa8d430ba56c7a5f9abe0183afefd3a2d6e483060343398b13fb1 \
|
||||
--hash=sha256:6e3e1ec10c29bae0ea826b61f265ec5c858c5ba2ce2e69a71a62f285cf8e4595 \
|
||||
--hash=sha256:727ece10e065be2f9dd239d15dd5d60a66e17eac11aea47d447f9f03fdbc42de \
|
||||
--hash=sha256:7339e6a3283e4b0ade99cade51e97cde3d54cd6d1c3744459e886b66d630c8b3 \
|
||||
--hash=sha256:767604f244dc17c68d3e2dbf98e038d11a18abc078f2d0f84b6c24571d9c0b13 \
|
||||
--hash=sha256:7a64edd3ff6a7f711a15bd70b4458611fb240176ec11ad8845ccbab4fe6745db \
|
||||
--hash=sha256:81aa97669cd726349eb7bd43ca540cf418b279ee3caba5e2e295fb4e8f841c02 \
|
||||
--hash=sha256:84c41ba992df5b8d680b89fd84c6a1f2aca2b9f1ae8a67400c8930cd4ea115f6 \
|
||||
--hash=sha256:84fd56c78d431606332a0627c16e2a63d243d0d8b05521257d77c6529abe14d8 \
|
||||
--hash=sha256:889e45e976c74abc7256d3064aa7c1295aa283c6bb19810b9f8b604dfe5c7f31 \
|
||||
--hash=sha256:8e2e12d0d862f43d51e5afb8b9751c77e6bec7d2dc00aad80641364e9df5b199 \
|
||||
--hash=sha256:967b65232e104f4b0f6370a62eb33089e00024f2ce143aecbf9755649421c683 \
|
||||
--hash=sha256:9d077f909f2343daf4495ba22bb0e23b62886e8ec7c109ee8234bdbd678cf344 \
|
||||
--hash=sha256:9d57b4e23ebbe985125d3f0cabbf286efa191ab60bbadb9326091050d88e8213 \
|
||||
--hash=sha256:a1968f2a2003c97c4ce6308dc2498d5fd4364ad309900930aa5a503c9851aec8 \
|
||||
--hash=sha256:a2a722c0e4bfd9966a11ff55c895c817158fcce1b2b6700205a376403b546ad9 \
|
||||
--hash=sha256:a97bb05eb24637714a04dee85bdf0ad1941df64fe3b802ee4ac1c284a5f97b7c \
|
||||
--hash=sha256:aff40f8ac6763d05c2c8f6d240c6dac4bb92640a86d9b0c3f3fff4404f34095c \
|
||||
--hash=sha256:babe8d1eb059a53e560e7bf29f8e8f4accc8b6cfb9b5fd10e485bde77e71ef41 \
|
||||
--hash=sha256:bbceffc80aa02d9e8b99f2a7491ed8c4a783b2fc4020119dc405ca14fb5c758c \
|
||||
--hash=sha256:c59375e85126b15a90fcba3443eaac58f3073ba091f02410eaa286da9ad80ed8 \
|
||||
--hash=sha256:ca2aed95855506b7ae94e8f1f6217b7673c929e4f4f1217bcaa236253055cb36 \
|
||||
--hash=sha256:cc066cb98b912f525ae901a24cd381a656f024f76203bc85f78fcc9e66ae5aec \
|
||||
--hash=sha256:cdef9a056c222d0479a1fdb721430f9efd68268014c54e8166133d2643cb05d9 \
|
||||
--hash=sha256:d07f1b64008e39fceae7aa99e38df8385d7d24a474a8c9872645c4397b674481 \
|
||||
--hash=sha256:d639397de852f2ccfb3134b152c741406752640a266d9c1365b0f23d7b88077f \
|
||||
--hash=sha256:dff02c5c8423a657c550b48231d0a48d7e2b2e131088e55983cfe74ccc2c7cc9 \
|
||||
--hash=sha256:e952c684274a7714b3160f57ec1d78309f955c6335c04433f07d36c5eb27b1f9 \
|
||||
--hash=sha256:ea1e9e43ca56b0c12440a7c689b1350066595bebcaa83baad05b8b2675129d98 \
|
||||
--hash=sha256:f022601f3ee9e1f6658ed6d184ce27fa5216cee5b82d279e0f0bde5deebece72 \
|
||||
--hash=sha256:f0e9618630edd1910ad4f07f60d77c184b2f572c8ee43305ea3265675cbbfe7e \
|
||||
--hash=sha256:f1d6bc9c23356908db712d282acb3eebd4ae5ec6d8b696aa40342b1d84f8e9e3 \
|
||||
--hash=sha256:f4376819c1c778d59e0a31db5dc6ede854e9edf28bbfa5b756604727f7f800ac
|
||||
# via -r requirements-fonttools.in
|
||||
markupsafe==2.1.3 \
|
||||
--hash=sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e \
|
||||
--hash=sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e \
|
||||
--hash=sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431 \
|
||||
--hash=sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686 \
|
||||
--hash=sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c \
|
||||
--hash=sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559 \
|
||||
--hash=sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc \
|
||||
--hash=sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb \
|
||||
--hash=sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939 \
|
||||
--hash=sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c \
|
||||
--hash=sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0 \
|
||||
--hash=sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4 \
|
||||
--hash=sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9 \
|
||||
--hash=sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575 \
|
||||
--hash=sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba \
|
||||
--hash=sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d \
|
||||
--hash=sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd \
|
||||
--hash=sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3 \
|
||||
--hash=sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00 \
|
||||
--hash=sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155 \
|
||||
--hash=sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac \
|
||||
--hash=sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52 \
|
||||
--hash=sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f \
|
||||
--hash=sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8 \
|
||||
--hash=sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b \
|
||||
--hash=sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007 \
|
||||
--hash=sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24 \
|
||||
--hash=sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea \
|
||||
--hash=sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198 \
|
||||
--hash=sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0 \
|
||||
--hash=sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee \
|
||||
--hash=sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be \
|
||||
--hash=sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2 \
|
||||
--hash=sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1 \
|
||||
--hash=sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707 \
|
||||
--hash=sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6 \
|
||||
--hash=sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c \
|
||||
--hash=sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58 \
|
||||
--hash=sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823 \
|
||||
--hash=sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779 \
|
||||
--hash=sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636 \
|
||||
--hash=sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c \
|
||||
--hash=sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad \
|
||||
--hash=sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee \
|
||||
--hash=sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc \
|
||||
--hash=sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2 \
|
||||
--hash=sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48 \
|
||||
--hash=sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7 \
|
||||
--hash=sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e \
|
||||
--hash=sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b \
|
||||
--hash=sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa \
|
||||
--hash=sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5 \
|
||||
--hash=sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e \
|
||||
--hash=sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb \
|
||||
--hash=sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9 \
|
||||
--hash=sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57 \
|
||||
--hash=sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc \
|
||||
--hash=sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc \
|
||||
--hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2 \
|
||||
--hash=sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11
|
||||
# via jinja2
|
||||
meson==1.7.0 \
|
||||
--hash=sha256:08efbe84803eed07f863b05092d653a9d348f7038761d900412fddf56deb0284 \
|
||||
--hash=sha256:ae3f12953045f3c7c60e27f2af1ad862f14dee125b4ed9bcb8a842a5080dbf85
|
||||
# via -r requirements.in
|
||||
ninja==1.11.1.3 \
|
||||
--hash=sha256:04d48d14ea7ba11951c156599ab526bdda575450797ff57c6fdf99b2554d09c7 \
|
||||
--hash=sha256:114ed5c61c8474df6a69ab89097a20749b769e2c219a452cb2fadc49b0d581b0 \
|
||||
--hash=sha256:17978ad611d8ead578d83637f5ae80c2261b033db0b493a7ce94f88623f29e1b \
|
||||
--hash=sha256:1ad2112c2b0159ed7c4ae3731595191b1546ba62316fc40808edecd0306fefa3 \
|
||||
--hash=sha256:2883ea46b3c5079074f56820f9989c6261fcc6fd873d914ee49010ecf283c3b2 \
|
||||
--hash=sha256:28aea3c1c280cba95b8608d50797169f3a34280e3e9a6379b6e340f0c9eaeeb0 \
|
||||
--hash=sha256:2b4879ea3f1169f3d855182c57dcc84d1b5048628c8b7be0d702b81882a37237 \
|
||||
--hash=sha256:53409151da081f3c198bb0bfc220a7f4e821e022c5b7d29719adda892ddb31bb \
|
||||
--hash=sha256:56ada5d33b8741d298836644042faddebc83ee669782d661e21563034beb5aba \
|
||||
--hash=sha256:7fa2247fce98f683bc712562d82b22b8a0a5c000738a13147ca2d1b68c122298 \
|
||||
--hash=sha256:8c4bdb9fd2d0c06501ae15abfd23407660e95659e384acd36e013b6dd7d8a8e4 \
|
||||
--hash=sha256:a27e78ca71316c8654965ee94b286a98c83877bfebe2607db96897bbfe458af0 \
|
||||
--hash=sha256:a38c6c6c8032bed68b70c3b065d944c35e9f903342875d3a3218c1607987077c \
|
||||
--hash=sha256:a4a3b71490557e18c010cbb26bd1ea9a0c32ee67e8f105e9731515b6e0af792e \
|
||||
--hash=sha256:b6966f83064a88a51693073eea3decd47e08c3965241e09578ef7aa3a7738329 \
|
||||
--hash=sha256:bc3ebc8b2e47716149f3541742b5cd8e0b08f51013b825c05baca3e34854370d \
|
||||
--hash=sha256:edfa0d2e9d7ead1635b03e40a32ad56cc8f56798b6e2e9848d8300b174897076
|
||||
ninja==1.11.1.4 \
|
||||
--hash=sha256:055f386fb550c2c9d6157e45e20a84d29c47968876b9c5794ae2aec46f952306 \
|
||||
--hash=sha256:096487995473320de7f65d622c3f1d16c3ad174797602218ca8c967f51ec38a0 \
|
||||
--hash=sha256:2ab67a41c90bea5ec4b795bab084bc0b3b3bb69d3cd21ca0294fc0fc15a111eb \
|
||||
--hash=sha256:4617b3c12ff64b611a7d93fd9e378275512bb36eff8babff7c83f5116b4f8d66 \
|
||||
--hash=sha256:5713cf50c5be50084a8693308a63ecf9e55c3132a78a41ab1363a28b6caaaee1 \
|
||||
--hash=sha256:6aa39f6e894e0452e5b297327db00019383ae55d5d9c57c73b04f13bf79d438a \
|
||||
--hash=sha256:9c29bb66d2aa46a2409ab369ea804c730faec7652e8c22c1e428cc09216543e5 \
|
||||
--hash=sha256:b33923c8da88e8da20b6053e38deb433f53656441614207e01d283ad02c5e8e7 \
|
||||
--hash=sha256:c3b96bd875f3ef1db782470e9e41d7508905a0986571f219d20ffed238befa15 \
|
||||
--hash=sha256:cede0af00b58e27b31f2482ba83292a8e9171cdb9acc2c867a3b6e40b3353e43 \
|
||||
--hash=sha256:cf4453679d15babc04ba023d68d091bb613091b67101c88f85d2171c6621c6eb \
|
||||
--hash=sha256:cf554e73f72c04deb04d0cf51f5fdb1903d9c9ca3d2344249c8ce3bd616ebc02 \
|
||||
--hash=sha256:cfdd09776436a1ff3c4a2558d3fc50a689fb9d7f1bdbc3e6f7b8c2991341ddb3 \
|
||||
--hash=sha256:d3090d4488fadf6047d0d7a1db0c9643a8d391f0d94729554dbb89b5bdc769d7 \
|
||||
--hash=sha256:d4a6f159b08b0ac4aca5ee1572e3e402f969139e71d85d37c0e2872129098749 \
|
||||
--hash=sha256:ecce44a00325a93631792974659cf253a815cc6da4ec96f89742925dfc295a0d \
|
||||
--hash=sha256:f6186d7607bb090c3be1e10c8a56b690be238f953616626f5032238c66e56867
|
||||
# via -r requirements.in
|
||||
|
||||
# The following packages are considered to be unsafe in a requirements file:
|
||||
setuptools==73.0.1 \
|
||||
--hash=sha256:b208925fcb9f7af924ed2dc04708ea89791e24bde0d3020b27df0e116088b34e \
|
||||
--hash=sha256:d59a3e788ab7e012ab2c4baed1b376da6366883ee20d7a5fc426816e3d7b1193
|
||||
setuptools==78.1.0 \
|
||||
--hash=sha256:18fd474d4a82a5f83dac888df697af65afa82dec7323d09c3e37d1f14288da54 \
|
||||
--hash=sha256:3e386e96793c8702ae83d17b853fb93d3e09ef82ec62722e61da5cd22376dcd8
|
||||
# via -r requirements.in
|
||||
|
|
|
@ -4,7 +4,7 @@ cpu_family = 'x86'
|
|||
cpu = 'i686'
|
||||
endian = 'little'
|
||||
|
||||
[properties]
|
||||
[built-in options]
|
||||
c_args = []
|
||||
c_link_args = ['-static-libgcc', '-Wl,-Bstatic', '-lpthread']
|
||||
cpp_args = []
|
||||
|
@ -18,3 +18,5 @@ ld = 'i686-w64-mingw32-ld'
|
|||
objcopy = 'i686-w64-mingw32-objcopy'
|
||||
strip = 'i686-w64-mingw32-strip'
|
||||
windres = 'i686-w64-mingw32-windres'
|
||||
pkg-config = 'i686-w64-mingw32-pkg-config'
|
||||
exe_wrapper = 'wine'
|
||||
|
|
|
@ -4,7 +4,7 @@ cpu_family = 'x86_64'
|
|||
cpu = 'x86_64'
|
||||
endian = 'little'
|
||||
|
||||
[properties]
|
||||
[built-in options]
|
||||
c_args = []
|
||||
c_link_args = ['-static-libgcc', '-Wl,-Bstatic', '-lpthread']
|
||||
cpp_args = []
|
||||
|
@ -18,3 +18,5 @@ ld = 'x86_64-w64-mingw32-ld'
|
|||
objcopy = 'x86_64-w64-mingw32-objcopy'
|
||||
strip = 'x86_64-w64-mingw32-strip'
|
||||
windres = 'x86_64-w64-mingw32-windres'
|
||||
pkg-config = 'x86_64-w64-mingw32-pkg-config'
|
||||
exe_wrapper = 'wine'
|
||||
|
|
|
@ -3,10 +3,10 @@ version: 2.1
|
|||
executors:
|
||||
win32-executor:
|
||||
docker:
|
||||
- image: cimg/base:2023.10
|
||||
- image: ubuntu:24.04
|
||||
win64-executor:
|
||||
docker:
|
||||
- image: cimg/base:2023.10
|
||||
- image: ubuntu:24.04
|
||||
dist-executor:
|
||||
docker:
|
||||
- image: cimg/base:2023.10
|
||||
|
@ -37,7 +37,7 @@ jobs:
|
|||
- run: meson dist --no-tests -Cbuild
|
||||
- persist_to_workspace:
|
||||
root: .
|
||||
paths: build/meson-dist/harfbuzz-*.tar.xz
|
||||
paths: [build/meson-dist/harfbuzz-*.tar.xz]
|
||||
|
||||
publish-dist:
|
||||
executor: dist-executor
|
||||
|
@ -58,20 +58,6 @@ jobs:
|
|||
- run: meson compile -Cbuild -j9
|
||||
- run: RUN_VALGRIND=1 meson test -Cbuild -t 10 --no-suite=slow --wrap='valgrind --leak-check=full --error-exitcode=1' --print-errorlogs --num-processes=$(($(nproc)/2 + 1))
|
||||
|
||||
alpine:
|
||||
docker:
|
||||
- image: alpine
|
||||
steps:
|
||||
- checkout
|
||||
- run: apk update && apk add ragel gcc g++ glib-dev freetype-dev cairo-dev git py3-pip ninja
|
||||
- run: |
|
||||
python3 -m venv venv
|
||||
source venv/bin/activate
|
||||
pip3 install meson==0.56.0
|
||||
meson setup build --buildtype=minsize
|
||||
meson compile -Cbuild -j9
|
||||
meson test -Cbuild --print-errorlogs
|
||||
|
||||
asan-ubsan:
|
||||
docker:
|
||||
- image: ubuntu
|
||||
|
@ -80,9 +66,11 @@ jobs:
|
|||
- run: apt update || true
|
||||
- run: DEBIAN_FRONTEND=noninteractive apt install -y python3 python3-pip python3-venv ninja-build clang lld git binutils pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev
|
||||
- run: |
|
||||
export ASAN_OPTIONS=log_path=stderr:halt_on_error=1:abort_on_error=1
|
||||
export UBSAN_OPTIONS=log_path=stderr:halt_on_error=1:abort_on_error=1:print_stacktrace=1
|
||||
python3 -m venv venv
|
||||
source venv/bin/activate
|
||||
pip3 install meson==0.56.0
|
||||
pip3 install meson==0.60.0
|
||||
CC=clang CXX=clang++ meson setup build --default-library=static -Db_sanitize=address,undefined --buildtype=debugoptimized --wrap-mode=nodownload -Dexperimental_api=true
|
||||
meson compile -Cbuild -j9
|
||||
meson test -Cbuild -t 10 --print-errorlogs | asan_symbolize | c++filt
|
||||
|
@ -95,9 +83,10 @@ jobs:
|
|||
- run: apt update || true
|
||||
- run: DEBIAN_FRONTEND=noninteractive apt install -y python3 python3-pip python3-venv ninja-build clang lld git binutils pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev
|
||||
- run: |
|
||||
export TSAN_OPTIONS=log_path=stderr:halt_on_error=1:abort_on_error=1
|
||||
python3 -m venv venv
|
||||
source venv/bin/activate
|
||||
pip3 install meson==0.56.0
|
||||
pip3 install meson==0.60.0
|
||||
CC=clang CXX=clang++ meson setup build --default-library=static -Db_sanitize=thread --buildtype=debugoptimized --wrap-mode=nodownload -Dexperimental_api=true
|
||||
meson compile -Cbuild -j9
|
||||
meson test -Cbuild -t 10 --print-errorlogs | asan_symbolize | c++filt
|
||||
|
@ -110,9 +99,10 @@ jobs:
|
|||
- run: apt update || true
|
||||
- run: DEBIAN_FRONTEND=noninteractive apt install -y python3 python3-pip python3-venv ninja-build clang lld git binutils pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev
|
||||
- run: |
|
||||
export MSAN_OPTIONS=log_path=stderr:halt_on_error=1:abort_on_error=1:print_stacktrace=1
|
||||
python3 -m venv venv
|
||||
source venv/bin/activate
|
||||
pip3 install meson==0.56.0
|
||||
pip3 install meson==0.60.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
|
||||
|
@ -131,17 +121,21 @@ jobs:
|
|||
executor: win32-executor
|
||||
steps:
|
||||
- checkout
|
||||
- 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: dpkg --add-architecture i386
|
||||
- run: apt update
|
||||
- run: DEBIAN_FRONTEND=noninteractive apt install -y ninja-build python3 python3-pip python3-venv git g++-mingw-w64-i686 zip wine wine32
|
||||
- run: |
|
||||
export LANG=en_US.UTF-8
|
||||
python3 -m venv venv
|
||||
source venv/bin/activate
|
||||
pip3 install meson==1.6.0
|
||||
bash .ci/build-win32.sh
|
||||
bash .ci/build-win.sh 32
|
||||
meson devenv -Cbuild-win32 meson test -t 10 --print-errorlogs --suite=harfbuzz
|
||||
- store_artifacts:
|
||||
path: harfbuzz-win32.zip
|
||||
- persist_to_workspace:
|
||||
root: .
|
||||
paths: harfbuzz-win32.zip
|
||||
paths: [harfbuzz-win32.zip]
|
||||
|
||||
publish-win32:
|
||||
executor: win32-executor
|
||||
|
@ -149,6 +143,8 @@ jobs:
|
|||
- checkout
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run: apt update
|
||||
- run: DEBIAN_FRONTEND=noninteractive apt install -y curl
|
||||
- run: |
|
||||
mv harfbuzz-win32{,-$CIRCLE_TAG}.zip
|
||||
.ci/publish_release_artifact.sh harfbuzz-win32-$CIRCLE_TAG.zip
|
||||
|
@ -157,17 +153,21 @@ jobs:
|
|||
executor: win64-executor
|
||||
steps:
|
||||
- checkout
|
||||
- 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: dpkg --add-architecture i386
|
||||
- run: apt update
|
||||
- run: DEBIAN_FRONTEND=noninteractive apt install -y ninja-build python3 python3-pip python3-venv git g++-mingw-w64-x86-64 zip wine wine64 wine32:i386
|
||||
- run: |
|
||||
export LANG=en_US.UTF-8
|
||||
python3 -m venv venv
|
||||
source venv/bin/activate
|
||||
pip3 install meson==1.6.0
|
||||
bash .ci/build-win64.sh
|
||||
bash .ci/build-win.sh 64
|
||||
meson devenv -Cbuild-win64 meson test -t 10 --print-errorlogs --suite=harfbuzz
|
||||
- store_artifacts:
|
||||
path: harfbuzz-win64.zip
|
||||
- persist_to_workspace:
|
||||
root: .
|
||||
paths: harfbuzz-win64.zip
|
||||
paths: [harfbuzz-win64.zip]
|
||||
|
||||
publish-win64:
|
||||
executor: win64-executor
|
||||
|
@ -175,6 +175,8 @@ jobs:
|
|||
- checkout
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run: apt update
|
||||
- run: DEBIAN_FRONTEND=noninteractive apt install -y curl
|
||||
- run: |
|
||||
mv harfbuzz-win64{,-$CIRCLE_TAG}.zip
|
||||
.ci/publish_release_artifact.sh harfbuzz-win64-$CIRCLE_TAG.zip
|
||||
|
@ -199,7 +201,6 @@ workflows:
|
|||
branches:
|
||||
ignore: /.*/
|
||||
- fedora-valgrind
|
||||
- alpine
|
||||
- asan-ubsan
|
||||
- tsan
|
||||
- msan
|
||||
|
|
2
.github/workflows/cifuzz.yml
vendored
2
.github/workflows/cifuzz.yml
vendored
|
@ -21,7 +21,7 @@ jobs:
|
|||
fuzz-seconds: 600
|
||||
dry-run: false
|
||||
- name: Upload Crash
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
if: failure() && steps.build.outcome == 'success'
|
||||
with:
|
||||
name: artifacts
|
||||
|
|
63
.github/workflows/fontations.yml
vendored
Normal file
63
.github/workflows/fontations.yml
vendored
Normal file
|
@ -0,0 +1,63 @@
|
|||
name: fontations
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
tags: ["*.*.*"]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- name: Setup Ccache
|
||||
uses: hendrikmuhs/ccache-action@a1209f81afb8c005c13b4296c32e363431bffea5 # v1.2.17
|
||||
with:
|
||||
key: ${{ github.job }}-${{ runner.os }}-${{ runner.arch }}
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
rustup component add \
|
||||
rust-src \
|
||||
rustfmt \
|
||||
clippy \
|
||||
--toolchain nightly-x86_64-unknown-linux-gnu
|
||||
sudo apt-get update
|
||||
sudo apt-get install \
|
||||
gcc \
|
||||
gobject-introspection \
|
||||
gtk-doc-tools \
|
||||
libcairo2-dev \
|
||||
libfreetype6-dev \
|
||||
libgirepository1.0-dev \
|
||||
libglib2.0-dev \
|
||||
libgraphite2-dev \
|
||||
libicu-dev \
|
||||
pkg-config \
|
||||
bindgen
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0
|
||||
with:
|
||||
python-version: '3.12'
|
||||
- name: Install Python Dependencies
|
||||
run: pip3 install -r .ci/requirements.txt --require-hashes
|
||||
- name: Setup Meson
|
||||
run: |
|
||||
ccache --version
|
||||
meson setup build \
|
||||
-Dauto_features=enabled \
|
||||
-Dchafa=disabled \
|
||||
-Dgraphite=enabled \
|
||||
-Doptimization=2 \
|
||||
-Dfontations=enabled
|
||||
- name: Build
|
||||
run: meson compile -Cbuild
|
||||
- name: Test
|
||||
run: RUST_BACKTRACE=1 meson test --print-errorlogs -Cbuild
|
5
.github/workflows/linux-ci.yml
vendored
5
.github/workflows/linux-ci.yml
vendored
|
@ -34,9 +34,10 @@ jobs:
|
|||
libglib2.0-dev \
|
||||
libgraphite2-dev \
|
||||
libicu-dev \
|
||||
pkg-config
|
||||
pkg-config \
|
||||
help2man
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
|
||||
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0
|
||||
with:
|
||||
python-version: '3.12'
|
||||
- name: Install Python Dependencies
|
||||
|
|
2
.github/workflows/macos-ci.yml
vendored
2
.github/workflows/macos-ci.yml
vendored
|
@ -36,7 +36,7 @@ jobs:
|
|||
ninja \
|
||||
pkgconf
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
|
||||
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0
|
||||
with:
|
||||
python-version: '3.12'
|
||||
- name: Install Python Dependencies
|
||||
|
|
2
.github/workflows/msvc-ci.yml
vendored
2
.github/workflows/msvc-ci.yml
vendored
|
@ -35,7 +35,7 @@ jobs:
|
|||
variant: sccache
|
||||
key: ${{ github.job }}-${{ matrix.os }}-${{ matrix.ARCH }}
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
|
||||
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0
|
||||
with:
|
||||
python-version: '3.12'
|
||||
- name: Setup MSVC
|
||||
|
|
17
.github/workflows/msys2-ci.yml
vendored
17
.github/workflows/msys2-ci.yml
vendored
|
@ -21,13 +21,10 @@ jobs:
|
|||
MSYS2_ARCH: i686
|
||||
- MSYSTEM: MINGW64
|
||||
MSYS2_ARCH: x86_64
|
||||
- MSYSTEM: CLANG64
|
||||
MSYS2_ARCH: clang-x86_64
|
||||
name: ${{ matrix.MSYSTEM }}
|
||||
|
||||
env:
|
||||
# XXX: For some reason enabling jit debugging "fixes" random python crashes
|
||||
# see https://github.com/msys2/MINGW-packages/issues/11864
|
||||
MSYS: "winjitdebug"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
|
@ -42,8 +39,7 @@ jobs:
|
|||
install: >-
|
||||
mingw-w64-${{ matrix.MSYS2_ARCH }}-cairo
|
||||
mingw-w64-${{ matrix.MSYS2_ARCH }}-freetype
|
||||
mingw-w64-${{ matrix.MSYS2_ARCH }}-gcc
|
||||
mingw-w64-${{ matrix.MSYS2_ARCH }}-gcc-libs
|
||||
mingw-w64-${{ matrix.MSYS2_ARCH }}-cc
|
||||
mingw-w64-${{ matrix.MSYS2_ARCH }}-gettext
|
||||
mingw-w64-${{ matrix.MSYS2_ARCH }}-glib2
|
||||
mingw-w64-${{ matrix.MSYS2_ARCH }}-gobject-introspection
|
||||
|
@ -51,12 +47,9 @@ jobs:
|
|||
mingw-w64-${{ matrix.MSYS2_ARCH }}-icu
|
||||
mingw-w64-${{ matrix.MSYS2_ARCH }}-meson
|
||||
mingw-w64-${{ matrix.MSYS2_ARCH }}-ninja
|
||||
mingw-w64-${{ matrix.MSYS2_ARCH }}-pkg-config
|
||||
mingw-w64-${{ matrix.MSYS2_ARCH }}-pkgconf
|
||||
mingw-w64-${{ matrix.MSYS2_ARCH }}-python
|
||||
mingw-w64-${{ matrix.MSYS2_ARCH }}-python-pip
|
||||
- name: Remove installed HarfBuzz DLLs
|
||||
run: |
|
||||
rm -f -v /ming*/bin/libharfbuzz-*.dll
|
||||
- name: Install Python Dependencies
|
||||
run: |
|
||||
pip3 install -r .ci/requirements-fonttools.txt --require-hashes
|
||||
|
@ -76,7 +69,7 @@ jobs:
|
|||
run: meson test --print-errorlogs --suite=harfbuzz -Cbuild
|
||||
- name: Upload DLLs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: libharfbuzz-${{ matrix.MSYS2_ARCH }}
|
||||
path: ./build/src/libharfbuzz-*.dll
|
||||
|
|
6
.github/workflows/scorecard.yml
vendored
6
.github/workflows/scorecard.yml
vendored
|
@ -34,7 +34,7 @@ jobs:
|
|||
persist-credentials: false
|
||||
|
||||
- name: "Run analysis"
|
||||
uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
|
||||
uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
|
@ -51,7 +51,7 @@ jobs:
|
|||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
||||
# format to the repository Actions tab.
|
||||
- name: "Upload artifact"
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
|
@ -59,6 +59,6 @@ jobs:
|
|||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@9e8d0789d4a0fa9ceb6b1738f7e269594bdd67f0 # v3.28.9
|
||||
uses: github/codeql-action/upload-sarif@fc7e4a0fa01c3cca5fd6a1fddec5c0740c977aa2 # v3.28.14
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
|
|
@ -233,7 +233,7 @@ if (HB_HAVE_FREETYPE AND NOT TARGET freetype)
|
|||
set (CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${FREETYPE_INCLUDE_DIRS})
|
||||
set (CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${FREETYPE_LIBRARIES})
|
||||
|
||||
check_funcs(FT_Get_Var_Blend_Coordinates FT_Set_Var_Blend_Coordinates FT_Done_MM_Var)
|
||||
check_funcs(FT_Get_Var_Blend_Coordinates FT_Set_Var_Blend_Coordinates FT_Done_MM_Var FT_Get_Transform)
|
||||
endif ()
|
||||
|
||||
if (HB_HAVE_FREETYPE)
|
||||
|
|
117
NEWS
117
NEWS
|
@ -1,7 +1,118 @@
|
|||
Overview of changes leading to 11.0.1
|
||||
Friday, April 4, 2025
|
||||
====================================
|
||||
- The change in version 10.3.0 to apply “trak” table tracking values to glyph
|
||||
advances directly has been reverted as it required every font functions
|
||||
implementation to handle it, which breaks existing custom font functions.
|
||||
Tracking is instead back to being applied during shaping.
|
||||
- When `directwrite` integration is enabled, we now link to `dwrite.dll`
|
||||
instead of dynamically loading it.
|
||||
- A new experimental APIs for getting raw “CFF” and “CFF2” CharStrings.
|
||||
- We now provide manpages for the various command line utilities. Building
|
||||
manpages requires “help2man” and will be skipped if it is not present.
|
||||
- The command line utilities now set different return value for different kinds
|
||||
of failures. Details are provided in the manpages.
|
||||
- Various fixes and improvements to `fontations` font functions.
|
||||
- All shaping operations using the `ot` shaper have become memory
|
||||
allocation-free.
|
||||
- Glyph extents returned by `hb-ot` and `hb-ft` font functions are now rounded
|
||||
in stead of flooring/ceiling them, which also matches what other font
|
||||
libraries do.
|
||||
- Fix “AAT” deleted glyph marks interfering with fallback mark positioning.
|
||||
- Glyph outlines emboldening have been moved out of `hb-ot` and `hb-ft` font
|
||||
functions to the HarfBuzz font layer, so that it works with any font
|
||||
functions implementation.
|
||||
- Fix our fallback C++11 atomics integration, which seems to not be widely
|
||||
used.
|
||||
- Various testing fixes and improvements.
|
||||
- Various subsetting fixes and improvements.
|
||||
- Various other fixes and improvements.
|
||||
|
||||
|
||||
Overview of changes leading to 11.0.0
|
||||
Monday, March 24, 2025
|
||||
====================================
|
||||
- There are three new font-functions implementations (integrations) in this
|
||||
release:
|
||||
* `hb-coretext` has gained one, calling into the CoreText library,
|
||||
* `hb-directwrite` has gained one, calling into the DirectWrite library.
|
||||
* `hb-fontations` has gained one, calling into the Skrifa Rust library.
|
||||
All three are mostly useful for performance and correctness testing, but some
|
||||
clients might find them useful.
|
||||
An API is added to use them from a single API by providing a backend name
|
||||
string:
|
||||
* `hb_font_set_funcs_using()`
|
||||
- Several new APIs are added, to load a font-face using different
|
||||
"face-loaders", and a single entry point to them all using a loader name
|
||||
string:
|
||||
* `hb_ft_face_create_from_file_or_fail()` and
|
||||
`hb_ft_face_create_from_blob_or_fail()`
|
||||
* `hb_coretext_face_create_from_file_or_fail()` and
|
||||
`hb_coretext_face_create_from_blob_or_fail()`
|
||||
* `hb_directwrite_face_create_from_file_or_fail()` and
|
||||
`hb_directwrite_face_create_from_blob_or_fail()`
|
||||
* `hb_face_create_from_file_or_fail_using()`
|
||||
- All drawing and painting operations using the default, `hb-ot` functions have
|
||||
become memory allocation-free.
|
||||
- Several performance optimizations have been implemented.
|
||||
- Application of the `trak` table during shaping has been improved.
|
||||
- The `directwrite` shaper now supports font variations, and correctly applies
|
||||
user features.
|
||||
- The `hb-directwrite` API and shaper has graduated from experimental.
|
||||
- Various bug fixes and other improvements.
|
||||
|
||||
- New API:
|
||||
+hb_malloc
|
||||
+hb_calloc
|
||||
+hb_realloc
|
||||
+hb_free
|
||||
+hb_face_list_loaders
|
||||
+hb_face_create_or_fail_using
|
||||
+hb_face_create_from_file_or_fail_using
|
||||
+hb_font_list_funcs
|
||||
+hb_font_set_funcs_using
|
||||
+hb_coretext_face_create_from_blob_or_fail
|
||||
+hb_directwrite_face_create_from_file_or_fail
|
||||
+hb_directwrite_face_create_from_blob_or_fail
|
||||
+hb_directwrite_font_create
|
||||
+hb_directwrite_font_get_dw_font_face
|
||||
+hb_directwrite_font_set_funcs
|
||||
+hb_fontations_font_set_funcs
|
||||
+hb_ft_face_create_from_blob_or_fail
|
||||
+hb_paint_push_font_transform
|
||||
+hb_paint_push_inverse_font_transform
|
||||
+HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES
|
||||
+HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE
|
||||
+HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES
|
||||
+HB_BUFFER_CLUSTER_LEVEL_IS_CHARACTERS
|
||||
|
||||
- Deprecated API:
|
||||
+hb_directwrite_font_get_dw_font
|
||||
|
||||
|
||||
Overview of changes leading to 10.4.0
|
||||
Saturday, March 1, 2025
|
||||
====================================
|
||||
- Drawing glyphs using hb-draw API now avoids any “malloc” calls, which
|
||||
improves drawing performance by 10+%.
|
||||
- Add support new “GVAR” table fonts with more than 65535 glyphs. Support is
|
||||
currently behind a compilation flag and is disabled by default.
|
||||
- Some hb-directwrite and hb-ft APIs got renamed with more clear names and the
|
||||
old names are deprecated.
|
||||
- Various build and fuzzing fixes.
|
||||
|
||||
- New API:
|
||||
+hb_directwrite_face_get_dw_font_face()
|
||||
+hb_ft_font_get_ft_face()
|
||||
|
||||
- Deprecated API:
|
||||
+hb_directwrite_face_get_font_face()
|
||||
+hb_ft_font_get_face()
|
||||
|
||||
|
||||
Overview of changes leading to 10.3.0
|
||||
Thursday, February 11, 2025
|
||||
====================================
|
||||
|
||||
- Vastly improved “AAT” shaping performance. LucidaGrande benchmark-shape
|
||||
before: 14.6ms after: 5.9ms.
|
||||
- Improved OpenType shaping performance (kerning / ligature), at the expense of
|
||||
|
@ -226,10 +337,10 @@ Saturday, November 11, 2023
|
|||
tools. Old option is kept as an alias.
|
||||
|
||||
- New API:
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_CURSIVE_CONNECTION
|
||||
+HB_AAT_LAYOUT_FEATURE_TYPE_CURSIVE_CONNECTION
|
||||
|
||||
- Deprecated API:
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION
|
||||
+HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION
|
||||
|
||||
Overview of changes leading to 8.2.2
|
||||
Wednesday, October 18, 2023
|
||||
|
|
72
README.md
72
README.md
|
@ -1,8 +1,9 @@
|
|||
[](https://github.com/harfbuzz/harfbuzz/workflows/linux-ci/badge.svg)
|
||||
[](https://github.com/harfbuzz/harfbuzz/actions/workflows/linux-ci.yml)
|
||||
[](https://github.com/harfbuzz/harfbuzz/actions/workflows/macos-ci.yml)
|
||||
[](https://github.com/harfbuzz/harfbuzz/actions/workflows/msvc-ci.yml)
|
||||
[](https://circleci.com/gh/harfbuzz/harfbuzz/tree/main)
|
||||
[](https://oss-fuzz-build-logs.storage.googleapis.com/index.html)
|
||||
[](https://oss-fuzz-build-logs.storage.googleapis.com/index.html#harfbuzz)
|
||||
[](https://scan.coverity.com/projects/harfbuzz)
|
||||
[](https://app.codacy.com/gh/harfbuzz/harfbuzz/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
|
||||
[](https://repology.org/project/harfbuzz/versions)
|
||||
[](https://securityscorecards.dev/viewer/?uri=github.com/harfbuzz/harfbuzz)
|
||||
|
||||
|
@ -34,13 +35,20 @@ will also find Win32/Win64 binary bundles that include `libharfbuzz` DLL,
|
|||
`hb-view.exe`, `hb-shape.exe`, and all dependencies.
|
||||
|
||||
The canonical source tree is available on [github][4].
|
||||
Both development and user support discussion around HarfBuzz happens on
|
||||
[github][4] as well.
|
||||
|
||||
The API that comes with `hb.h` will not change incompatibly. Other, peripheral,
|
||||
headers are more likely to go through minor modifications, but again, we do our
|
||||
best to never change API in an incompatible way. We will never break the ABI.
|
||||
|
||||
If you are not sure whether Pango or HarfBuzz is right for you, read [Pango vs
|
||||
HarfBuzz][5].
|
||||
The API and ABI are stable even across major version number jumps. In fact,
|
||||
current HarfBuzz is API/ABI compatible all the way back to the 0.9.x series.
|
||||
If one day we need to break the API/ABI, that would be called a new a library.
|
||||
|
||||
As such, we bump the major version number only when we add major new features,
|
||||
the minor version when there is new API, and the micro version when there
|
||||
are bug fixes.
|
||||
|
||||
## Development
|
||||
|
||||
|
@ -50,24 +58,38 @@ For custom configurations, see [CONFIG.md](CONFIG.md).
|
|||
|
||||
For testing and profiling, see [TESTING.md](TESTING.md).
|
||||
|
||||
For using with Python, see [README.python.md](README.python.md). There is also [uharfbuzz](https://github.com/harfbuzz/uharfbuzz).
|
||||
|
||||
For cross-compiling to Windows from Linux or macOS, see [README.mingw.md](README.mingw.md).
|
||||
|
||||
To report bugs or submit patches please use [github][4] issues and pull-requests.
|
||||
|
||||
### Developer documents
|
||||
|
||||
To get a better idea of where HarfBuzz stands in the text rendering stack you
|
||||
may want to read [State of Text Rendering 2024][6].
|
||||
Here are a few presentation slides about HarfBuzz at the
|
||||
Internationalization and Unicode Conference over the years:
|
||||
|
||||
* November 2014, [Unicode, OpenType, and HarfBuzz: Closing the Circle][7],
|
||||
* October 2012, [HarfBuzz, The Free and Open Text Shaping Engine][8],
|
||||
* October 2009, [HarfBuzz: the Free and Open Shaping Engine][9].
|
||||
- 2014 – [Unicode, OpenType, and HarfBuzz: Closing the Circle][7]
|
||||
- 2012 – [HarfBuzz, The Free and Open Text Shaping Engine][8]
|
||||
- 2016 – [Ten Years of HarfBuzz][20]
|
||||
- 2009 – [HarfBuzz: the Free and Open Shaping Engine][9]
|
||||
|
||||
Both development and user support discussion around HarfBuzz happens on the
|
||||
[github][4].
|
||||
More presentations and papers are available on [behdad][11]'s website.
|
||||
In particular, the following _studies_ are relevant to HarfBuzz development:
|
||||
|
||||
To report bugs or submit patches please use [github][4] issues and
|
||||
pull-requests.
|
||||
- 2025 – [Subsetting][21]
|
||||
- 2025 – [Caching][12]
|
||||
- 2025 – [`hb-decycler`][13]
|
||||
- 2022 – [`hb-iter`][14]
|
||||
- 2022 – [A C library written in C++][15]
|
||||
- 2022 – [The case of the slow `hb-ft` `>h_advance` function][18]
|
||||
- 2022 – [PackTab: A static integer table packer][16]
|
||||
- 2020 – [HarfBuzz OT+AAT "Unishaper"][19]
|
||||
- 2014 – [Building the Indic Shaper][17]
|
||||
- 2012 – [Memory Consumption][10]
|
||||
|
||||
For a comparison of old vs new HarfBuzz memory consumption see [this][10].
|
||||
|
||||
<!--See past and upcoming [HarfBuzz Hackfests](https://freedesktop.org/wiki/Software/HarfBuzz/Hackfests/)!-->
|
||||
|
||||
## Name
|
||||
|
||||
|
@ -84,6 +106,8 @@ transliterated using the Latin script. It also means "talkative" or
|
|||
> TrueType that adds support for complex script rendering, and HarfBuzz is an
|
||||
> implementation of OpenType complex text shaping.
|
||||
|
||||
## Distribution
|
||||
|
||||
<details>
|
||||
<summary>Packaging status of HarfBuzz</summary>
|
||||
|
||||
|
@ -95,9 +119,19 @@ transliterated using the Latin script. It also means "talkative" or
|
|||
[2]: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6AATIntro.html
|
||||
[3]: https://github.com/harfbuzz/harfbuzz/releases
|
||||
[4]: https://github.com/harfbuzz/harfbuzz
|
||||
[5]: http://mces.blogspot.com/2009/11/pango-vs-harfbuzz.html
|
||||
[6]: http://behdad.org/text2024
|
||||
[7]: https://goo.gl/FSIQuC
|
||||
[8]: https://goo.gl/2wSRu
|
||||
[7]: https://docs.google.com/presentation/d/1x97pfbB1gbD53Yhz6-_yBUozQMVJ_5yMqqR_D-R7b7I/preview
|
||||
[8]: https://docs.google.com/presentation/d/1ySTZaXP5XKFg0OpmHZM00v5b17GSr3ojnzJekl4U8qI/preview
|
||||
[9]: http://behdad.org/download/Presentations/slippy/harfbuzz_slides.pdf
|
||||
[10]: https://goo.gl/woyty
|
||||
[10]: https://docs.google.com/document/d/12jfNpQJzeVIAxoUSpk7KziyINAa1msbGliyXqguS86M/preview
|
||||
[11]: https://behdad.org/
|
||||
[12]: https://docs.google.com/document/d/1_VgObf6Je0J8byMLsi7HCQHnKo2emGnx_ib_sHo-bt4/preview
|
||||
[13]: https://docs.google.com/document/d/1Y-u08l9YhObRVObETZt1k8f_5lQdOix9TRH3zEXaoAw/preview
|
||||
[14]: https://docs.google.com/document/d/1o-xvxCbgMe9JYFHLVnPjk01ZY_8Cj0vB9-KTI1d0nyk/preview
|
||||
[15]: https://docs.google.com/document/d/18hI56KJpvXtwWbc9QSaz9zzhJwIMnrJ-zkAaKS-W-8k/preview
|
||||
[16]: https://docs.google.com/document/d/1Xq3owVt61HVkJqbLFHl73il6pcTy6PdPJJ7bSouQiQw/preview
|
||||
[17]: https://docs.google.com/document/d/1wMPwVNBvsIriamcyBO5aNs7Cdr8lmbwLJ8GmZBAswF4/preview
|
||||
[18]: https://docs.google.com/document/d/1wskYbA-czBt57oH9gEuGf3sWbTx7bfOiEIcDs36-heo/preview
|
||||
[19]: https://prezi.com/view/THNPJGFVDUCWoM20syev/
|
||||
[20]: https://behdad.org/doc/harfbuzz10years-slides.pdf
|
||||
[21]: https://docs.google.com/document/d/1_vZrt97OorJ0jA1YzJ29LRcGr3YGrNJANdOABjVZGEs/preview
|
||||
|
|
216
README.mingw.md
Normal file
216
README.mingw.md
Normal file
|
@ -0,0 +1,216 @@
|
|||
Most HarfBuzz developers do so on Linux or macOS. However, HarfBuzz is a
|
||||
cross-platform library and it is important to ensure that it works on Windows
|
||||
as well. In particular, we use this workflow to develop and test the HarfBuzz
|
||||
Uniscribe shaper and DirectWrite shaper and font backend, all from Linux or
|
||||
macOS.
|
||||
|
||||
This document provides instructions for cross-compiling HarfBuzz on Linux or
|
||||
macOS, for Windows, using the MinGW toolchain, and running tests and utilties
|
||||
under Wine.
|
||||
|
||||
We then discuss using native Windows Uniscribe or DirectWrite DLLs, which
|
||||
allows you to test HarfBuzz's shaping against the Microsoft shaping engines
|
||||
instead of those provided by Wine.
|
||||
|
||||
This document assumes that you are familiar with building HarfBuzz on Linux or
|
||||
macOS.
|
||||
|
||||
You can build for 32bit or 64bit Windows. If your intention is to use a native
|
||||
Uniscribe usp10.dll from Windows 7 or before, you would need to build for 32bit.
|
||||
If you want to use a native DirectWrite DLL from Windows 10 or later, you would
|
||||
need to build for 64bit.
|
||||
|
||||
We suggest you read to the end of this document before starting, as it provides
|
||||
a few different ways to build and test HarfBuzz for Windows.
|
||||
|
||||
1. Install Wine.
|
||||
|
||||
- Fedora: `dnf install wine`.
|
||||
- Ubuntu, 32bit: `apt install wine wine32`.
|
||||
- Ubuntu, 64bit: `apt install wine wine64`.
|
||||
- Mac: `brew install wine-stable`.
|
||||
|
||||
Note that to run Wine on Apple silicon systems, you need the Apple Rosetta translator.
|
||||
Follow the instructions you got from brew. This should do it:
|
||||
|
||||
- `softwareupdate --install-rosetta --agree-to-license`
|
||||
|
||||
2. Install the `mingw-w64` cross-compiler.
|
||||
|
||||
- Fedora, 32bit: `dnf install mingw32-gcc-c++`
|
||||
- Fedora, 64bit: `dnf install mingw64-gcc-c++`
|
||||
- Ubuntu, 32bit: `apt install g++-mingw-w64-i686`
|
||||
- Ubuntu, 64bit: `apt install g++-mingw-w64-x86-64`
|
||||
- Mac: `brew install mingw-w64`
|
||||
|
||||
3. Install dependencies.
|
||||
|
||||
First, make sure you do not have the mingw32 harfbuzz package, as that will
|
||||
override our own build with older `meson`:
|
||||
|
||||
- Fedora, 32bit: `dnf remove mingw32-harfbuzz`
|
||||
- Fedora, 64bit: `dnf remove mingw64-harfbuzz`
|
||||
|
||||
Then install the actual dependencies:
|
||||
|
||||
- Fedora, 32bit: `dnf install mingw32-glib2 mingw32-cairo mingw32-freetype`
|
||||
- Fedora, 64bit: `dnf install mingw64-glib2 mingw64-cairo mingw64-freetype`
|
||||
|
||||
If you cannot find these packages for your distribution, or you are on macOS,
|
||||
you can skip to the next step, as meson will automatically download and build
|
||||
the dependencies for you.
|
||||
|
||||
4. If you are familiar with `meson`, you can use the cross-compile files we
|
||||
provide to find your way around. But we do not recommend this way. Read until
|
||||
the end of this section before deciding which one to use.
|
||||
|
||||
- 32bit: `meson --cross-file=.ci/win32-cross-file.txt build-win -Dglib-enabled -Dcairo=enabled -Dgdi=enabled -Ddirectwrite=enabled`
|
||||
- 64bit: `meson --cross-file=.ci/win64-cross-file.txt build-win -Dglib-enabled -Dcairo=enabled -Dgdi=enabled -Ddirectwrite=enabled`
|
||||
|
||||
In which case, you will proceed to run `ninja` as usual to build:
|
||||
|
||||
- `ninja -C build-win`
|
||||
|
||||
Or you can simply invoke the scripts we provide for our Continuous Integration
|
||||
system, to configure and build HarfBuzz for you. This is the easiest way to
|
||||
build HarfBuzz for Windows and how we build our Windows binaries:
|
||||
|
||||
- 32bit: `./.ci/build-win.sh 32 && ln -s build-win32 build-win`
|
||||
- 64bit: `./.ci/build-win.sh 64 && ln -s build-win64 build-win`
|
||||
|
||||
This might take a while, since, if you do not have the dependencies installed,
|
||||
meson will download and build them for you.
|
||||
|
||||
5. If everything succeeds, you should have the `hb-shape.exe`, `hb-view.exe`,
|
||||
`hb-subset.exe`, and `hb-info.exe` executables in `build-win/util`.
|
||||
|
||||
6. Configure your wine to find system mingw libraries. While there, set it also
|
||||
to find the built HarfBuzz DLLs:
|
||||
|
||||
- Fedora, 32bit: `export WINEPATH="$HOME/harfbuzz/build-win/src;/usr/i686-w64-mingw32/sys-root/mingw/bin"`
|
||||
- Fedora, 64bit: `export WINEPATH="$HOME/harfbuzz/build-win/src;/usr/x86_64-w64-mingw32/sys-root/mingw/bin"`
|
||||
- Other systems: `export WINEPATH="$HOME/harfbuzz/build-win/src"`
|
||||
|
||||
Adjust for the path where you have built HarfBuzz. You might want to add this
|
||||
to your `.bashrc` or `.zshrc` file.
|
||||
|
||||
Alternatively, can skip this step if commands are run through the `meson devenv`
|
||||
command, which we will introduce in the next step. I personally find it more
|
||||
convenient to set the `WINEPATH` variable, as it allows me to run the executables
|
||||
directly from the shell.
|
||||
|
||||
7. Run the `hb-shape` executable under Wine:
|
||||
|
||||
- `wine build-win/util/hb-shape.exe perf/fonts/Roboto-Regular.ttf Test`
|
||||
|
||||
Or using `meson devenv to do the same:
|
||||
|
||||
- `meson devenv -C build-win util/hb-shape.exe $PWD/perf/fonts/Roboto-Regular.ttf Test`
|
||||
|
||||
You probably will get lots of Wine warnings, but if all works fine, you
|
||||
should see:
|
||||
```
|
||||
[gid57=0+1123|gid74=1+1086|gid88=2+1057|gid89=3+670]
|
||||
```
|
||||
|
||||
You can make Wine less verbose, without hiding all errors, by setting:
|
||||
|
||||
- `export WINEDEBUG=fixme-all,warn-all,err-plugplay,err-seh,err-rpc,err-ntoskrnl,err-winediag,err-systray,err-hid`
|
||||
|
||||
Add this to your `.bashrc` or `.zshrc` file as well.
|
||||
|
||||
Next, let's try some non-Latin text. Unfortunately, the command-line parsing of
|
||||
our cross-compiled glib is not quite Unicode-aware, at least when run under
|
||||
Wine. So you will need to find some other way to feed Unicode text to the
|
||||
shaper. There are three different ways you can try:
|
||||
|
||||
- `echo حرف | wine build-win/util/hb-shape.exe perf/fonts/Amiri-Regular.ttf`
|
||||
- `wine build-win/util/hb-shape.exe perf/fonts/Amiri-Regular.ttf -u 062D,0631,0641`
|
||||
- `wine build-win/util/hb-shape.exe perf/fonts/Amiri-Regular.ttf --text-file harf.txt`
|
||||
|
||||
To get the Unicode codepoints for a string, you can use the `hb-unicode-decode`
|
||||
utility:
|
||||
```
|
||||
$ test/shape/hb-unicode-decode حرف
|
||||
U+062D,U+0631,U+0641
|
||||
```
|
||||
|
||||
8. Next, let's try the `hb-view` utility. By default, `hb-view` outputs ANSI text,
|
||||
which Wine will not display correctly. You can use the `-o` option to redirect the
|
||||
output to a file, or just redirect the output using the shell, which will produce
|
||||
a PNG file.
|
||||
|
||||
- `wine build-win/util/hb-view.exe perf/fonts/Roboto-Regular.ttf Test > test.png`
|
||||
|
||||
7. As noted, if your Linux has `binfmt_misc` enabled, you can run the executables
|
||||
directly. If not, you can modify the cross-file to use the `exe_wrapper` option as
|
||||
specified before.
|
||||
|
||||
- `build-win/util/hb-shape.exe perf/fonts/Roboto-Regular.ttf Test`
|
||||
|
||||
If that does not work, you can use the `wine` command as shown above.
|
||||
|
||||
10. You can try running the test suite. If on Linux with `binfmt_misc` enabled, you
|
||||
can run the tests directly:
|
||||
|
||||
- `ninja -C build-win test`
|
||||
|
||||
For other situations, use `meson devenv`:
|
||||
|
||||
- `meson devenv -C build-win ninja test`
|
||||
|
||||
This might take a couple of minutes to run. Running under Wine is expensive, so
|
||||
be patient.
|
||||
|
||||
If all goes well, tests should run. If all is well, you should probably see about
|
||||
400 tests pass, some skipped, but none failing.
|
||||
|
||||
11. In the above testing situation, the `directwrite` test will be disabled
|
||||
automatically upon detection of running under Wine. The reason the `directwrite`
|
||||
test would otherwise fails is that we are running against the Wine-provided
|
||||
DirectWrite DLL, which is an incomplete reimplementation of the DirectWrite API
|
||||
by Wine, and not the real thing.
|
||||
|
||||
If you want to test the Uniscribe or DirectWrite shapers against the real
|
||||
Uniscribe / DirectWrite, you can follow the instructions below.
|
||||
|
||||
11. Old Uniscribe: Assuming a 32bit build for now.
|
||||
|
||||
Bring a 32bit version of `usp10.dll` for yourself from
|
||||
`C:\Windows\SysWOW64\usp10.dll` of your 64bit Windows installation,
|
||||
or `C:\Windows\System32\usp10.dll` for 32bit Windows installation.
|
||||
|
||||
You want one from Windows 7 or earlier. One that is not just a proxy for
|
||||
`TextShaping.dll`. Rule of thumb, your `usp10.dll` should have a size more
|
||||
than 500kb.
|
||||
|
||||
Put the file in `~/.wine/drive_c/windows/syswow64/` so wine can find it.
|
||||
|
||||
You can now tell wine to use the native `usp10.dll`:
|
||||
|
||||
- `export WINEDLLOVERRIDES="usp10=n"`
|
||||
- `wine build-win/util/hb-shape.exe perf/fonts/Roboto-Regular.ttf Test --shaper=uniscribe`
|
||||
|
||||
12. DirectWrite and new Uniscribe: You can use the same method to test the
|
||||
DirectWrite shaper against the native DirectWrite DLL. Try with a 64bit build
|
||||
this time.
|
||||
|
||||
Bring `TextShaping.dll`, `DWrite.dll`, and `usp10.dll` from your 64bit Windows
|
||||
installation (`C:\Windows\System32`) to `~/.wine/drive_c/windows/system32/`.
|
||||
|
||||
You want the ones from Windows 10 or later. You might have some luck downloading
|
||||
them from the internet, but be careful with the source. I had success with the
|
||||
DLLs from [https://dllme.com](dllme.com), but I cannot vouch for the site.
|
||||
|
||||
You can now tell wine to use the native DirectWrite:
|
||||
|
||||
- `export WINEDLLOVERRIDES="textshaping,dwrite,usp10=n"`
|
||||
- `wine build-win/util/hb-shape.exe perf/fonts/Roboto-Regular.ttf Test --shaper=directwrite`
|
||||
|
||||
If all works well, you should be able to rerun the tests and see all pass this time.
|
||||
|
||||
13. For some old instructions on how to test HarfBuzz's native Indic shaper against
|
||||
Uniscribe, see: https://github.com/harfbuzz/harfbuzz/issues/3671
|
||||
|
||||
14. That's it! If you made it this far, you are now able to develop and test
|
||||
HarfBuzz on Windows, from Linux or macOS. Enjoy!
|
22
RELEASING.md
22
RELEASING.md
|
@ -3,21 +3,21 @@
|
|||
- [ ] Open gitk and review changes since last release.
|
||||
|
||||
- [ ] Print all public API changes:
|
||||
`git diff $(git describe | sed 's/-.*//').. src/*.h`
|
||||
`git diff $(git describe | sed 's/-.*//').. src/*.h`
|
||||
|
||||
- [ ] Document them in NEWS.
|
||||
All API and API semantic changes should be clearly marked as API additions, API changes, or API deletions.
|
||||
All API and API semantic changes should be clearly marked as API additions, API changes, or API deletions.
|
||||
|
||||
- [ ] Document deprecations.
|
||||
Ensure all new API / deprecations are in listed correctly in docs/harfbuzz-sections.txt.
|
||||
If release added new API, add entry for new API index at the end of docs/harfbuzz-docs.xml.
|
||||
Ensure all new API / deprecations are listed correctly in docs/harfbuzz-sections.txt.
|
||||
If release added new API, add entry for new API index at the end of docs/harfbuzz-docs.xml.
|
||||
|
||||
If there's a backward-incompatible API change (including deletions for API used anywhere), that's a release blocker.
|
||||
Do NOT release.
|
||||
If there's a backward-incompatible API change (including deletions for API used anywhere), that's a release blocker.
|
||||
Do NOT release.
|
||||
|
||||
- [ ] Based on severity of changes, decide whether it's a minor or micro release number bump.
|
||||
|
||||
- [ ] Search for 'XSince: REPLACEME' on the repository and replace it with the chosen version for the release, e.g. 'Since: 1.4.7'.
|
||||
- [ ] Search for 'REPLACEME' on the repository and replace it with the chosen version for the release, e.g. 'Since: 1.4.7'.
|
||||
|
||||
- [ ] Make sure you have correct date and new version at the top of NEWS file.
|
||||
|
||||
|
@ -26,12 +26,16 @@
|
|||
- [ ] Do a `meson test -Cbuild` so it both checks the tests and updates hb-version.h (use `git diff` to see if is really updated).
|
||||
|
||||
- [ ] Commit NEWS, meson.build, and src/hb-version.h, as well as any REPLACEME changes you made.
|
||||
The commit message is simply the release number, e. g. "1.4.7"
|
||||
The commit message is simply the release number, e. g. "1.4.7"
|
||||
|
||||
- [ ] Do a `meson dist -Cbuild` that runs the tests against the latest committed changes.
|
||||
If doesn't pass, something fishy is going on, reset the repo and start over.
|
||||
If it does not pass, something fishy is going on, reset the repo and start over.
|
||||
|
||||
- [ ] Tag the release and sign it: e.g. `git tag -s 1.4.7 -m 1.4.7`.
|
||||
Enter your GPG password.
|
||||
|
||||
- [ ] Push the commit and tag out: `git push --follow-tags`.
|
||||
|
||||
- [ ] There should be a GitHub release automatically created.
|
||||
When it does, go to that release page and add description.
|
||||
The description should be the NEWS file additions.
|
||||
|
|
|
@ -90,15 +90,16 @@
|
|||
|
||||
<chapter id="integration-api">
|
||||
<title>Integration API</title>
|
||||
<xi:include href="xml/hb-cairo.xml"/>
|
||||
<xi:include href="xml/hb-coretext.xml"/>
|
||||
<xi:include href="xml/hb-directwrite.xml"/>
|
||||
<xi:include href="xml/hb-ft.xml"/>
|
||||
<xi:include href="xml/hb-fontations.xml"/>
|
||||
<xi:include href="xml/hb-gdi.xml"/>
|
||||
<xi:include href="xml/hb-glib.xml"/>
|
||||
<xi:include href="xml/hb-graphite2.xml"/>
|
||||
<xi:include href="xml/hb-icu.xml"/>
|
||||
<xi:include href="xml/hb-uniscribe.xml"/>
|
||||
<xi:include href="xml/hb-gdi.xml"/>
|
||||
<xi:include href="xml/hb-directwrite.xml"/>
|
||||
<xi:include href="xml/hb-cairo.xml"/>
|
||||
</chapter>
|
||||
|
||||
<chapter id="style-api">
|
||||
|
@ -120,6 +121,8 @@
|
|||
<index id="api-index-full"><title>API Index</title><xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="deprecated-api-index"><title>Index of deprecated API</title><xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include></index>
|
||||
|
||||
<index id="api-index-11-0-0"><title>Index of new symbols in 11.0.0</title><xi:include href="xml/api-index-11.0.0.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-10-4-0"><title>Index of new symbols in 10.4.0</title><xi:include href="xml/api-index-10.4.0.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-10-3-0"><title>Index of new symbols in 10.3.0</title><xi:include href="xml/api-index-10.3.0.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-10-2-0"><title>Index of new symbols in 10.2.0</title><xi:include href="xml/api-index-10.2.0.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-10-1-0"><title>Index of new symbols in 10.1.0</title><xi:include href="xml/api-index-10.1.0.xml"><xi:fallback /></xi:include></index>
|
||||
|
|
|
@ -114,6 +114,9 @@ hb_glyph_position_t
|
|||
hb_buffer_content_type_t
|
||||
hb_buffer_flags_t
|
||||
hb_buffer_cluster_level_t
|
||||
HB_BUFFER_CLUSTER_LEVEL_IS_CHARACTERS
|
||||
HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES
|
||||
HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE
|
||||
hb_segment_properties_t
|
||||
hb_buffer_serialize_format_t
|
||||
hb_buffer_serialize_flags_t
|
||||
|
@ -181,6 +184,10 @@ uint8_t
|
|||
HB_EXTERN
|
||||
HB_DEPRECATED
|
||||
HB_DEPRECATED_FOR
|
||||
hb_malloc
|
||||
hb_calloc
|
||||
hb_realloc
|
||||
hb_free
|
||||
<SUBSECTION Private>
|
||||
HB_H_IN
|
||||
HB_OT_H_IN
|
||||
|
@ -285,6 +292,8 @@ hb_paint_custom_palette_color_func_t
|
|||
hb_paint_funcs_set_custom_palette_color_func
|
||||
|
||||
hb_paint_push_transform
|
||||
hb_paint_push_font_transform
|
||||
hb_paint_push_inverse_font_transform
|
||||
hb_paint_pop_transform
|
||||
hb_paint_color_glyph
|
||||
hb_paint_push_clip_glyph
|
||||
|
@ -332,6 +341,10 @@ hb_font_funcs_set_glyph_shape_func
|
|||
hb_font_get_glyph_v_kerning
|
||||
hb_font_get_glyph_v_kerning_func_t
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION
|
||||
hb_directwrite_face_get_font_face
|
||||
hb_directwrite_font_get_dw_font
|
||||
hb_ft_font_get_face
|
||||
hb_graphite2_font_get_gr_font
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
|
@ -341,6 +354,7 @@ HB_CORETEXT_TAG_MORT
|
|||
HB_CORETEXT_TAG_MORX
|
||||
hb_coretext_face_create
|
||||
hb_coretext_face_create_from_file_or_fail
|
||||
hb_coretext_face_create_from_blob_or_fail
|
||||
hb_coretext_font_create
|
||||
hb_coretext_face_get_cg_font
|
||||
hb_coretext_font_get_ct_font
|
||||
|
@ -350,9 +364,12 @@ hb_coretext_font_set_funcs
|
|||
<SECTION>
|
||||
<FILE>hb-directwrite</FILE>
|
||||
hb_directwrite_face_create
|
||||
hb_directwrite_face_get_font_face
|
||||
hb_directwrite_face_create_from_file_or_fail
|
||||
hb_directwrite_face_create_from_blob_or_fail
|
||||
hb_directwrite_face_get_dw_font_face
|
||||
hb_directwrite_font_create
|
||||
hb_directwrite_font_get_dw_font
|
||||
hb_directwrite_font_get_dw_font_face
|
||||
hb_directwrite_font_set_funcs
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
|
@ -361,7 +378,10 @@ hb_face_count
|
|||
hb_face_t
|
||||
hb_face_create
|
||||
hb_face_create_or_fail
|
||||
hb_face_create_or_fail_using
|
||||
hb_face_create_from_file_or_fail
|
||||
hb_face_create_from_file_or_fail_using
|
||||
hb_face_list_loaders
|
||||
hb_reference_table_func_t
|
||||
hb_face_create_for_tables
|
||||
hb_face_get_empty
|
||||
|
@ -455,6 +475,8 @@ hb_font_get_serial
|
|||
hb_font_changed
|
||||
hb_font_set_funcs
|
||||
hb_font_set_funcs_data
|
||||
hb_font_set_funcs_using
|
||||
hb_font_list_funcs
|
||||
hb_font_subtract_glyph_origin_for_direction
|
||||
hb_font_funcs_create
|
||||
hb_font_funcs_get_empty
|
||||
|
@ -514,16 +536,23 @@ hb_font_extents_t
|
|||
hb_glyph_extents_t
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-fontations</FILE>
|
||||
hb_fontations_font_set_funcs
|
||||
</SECTION>
|
||||
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-ft</FILE>
|
||||
hb_ft_face_create
|
||||
hb_ft_face_create_cached
|
||||
hb_ft_face_create_referenced
|
||||
hb_ft_face_create_from_file_or_fail
|
||||
hb_ft_face_create_from_blob_or_fail
|
||||
hb_ft_font_create
|
||||
hb_ft_font_create_referenced
|
||||
hb_ft_font_changed
|
||||
hb_ft_font_get_face
|
||||
hb_ft_font_get_ft_face
|
||||
hb_ft_font_lock_face
|
||||
hb_ft_font_unlock_face
|
||||
hb_ft_font_set_load_flags
|
||||
|
@ -549,7 +578,6 @@ hb_glib_blob_create
|
|||
<FILE>hb-graphite2</FILE>
|
||||
HB_GRAPHITE2_TAG_SILF
|
||||
hb_graphite2_face_get_gr_face
|
||||
hb_graphite2_font_get_gr_font
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
|
@ -927,6 +955,10 @@ hb_subset_serialize_object_t
|
|||
hb_subset_serialize_or_fail
|
||||
<SUBSECTION Private>
|
||||
hb_subset_input_override_name_table
|
||||
hb_subset_cff_get_charstring_data
|
||||
hb_subset_cff_get_charstrings_index
|
||||
hb_subset_cff2_get_charstring_data
|
||||
hb_subset_cff2_get_charstrings_index
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
|
|
128
meson.build
128
meson.build
|
@ -1,11 +1,12 @@
|
|||
project('harfbuzz', 'c', 'cpp',
|
||||
meson_version: '>= 0.55.0',
|
||||
version: '10.3.0',
|
||||
project('harfbuzz', ['c', 'cpp'],
|
||||
meson_version: '>= 0.60.0',
|
||||
version: '11.0.1',
|
||||
default_options: [
|
||||
'cpp_eh=none', # Just to support msvc, we are passing -fno-exceptions also anyway
|
||||
# 'cpp_rtti=false', # Do NOT enable, wraps inherit it and ICU needs RTTI
|
||||
'cpp_std=c++11',
|
||||
'wrap_mode=nofallback', # Use --wrap-mode=default to revert, https://github.com/harfbuzz/harfbuzz/pull/2548
|
||||
'buildtype=debugoptimized',
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -102,44 +103,36 @@ check_funcs = [
|
|||
|
||||
m_dep = cpp.find_library('m', required: false)
|
||||
|
||||
if meson.version().version_compare('>=0.60.0')
|
||||
# Painful hack to handle multiple dependencies but also respect options
|
||||
if get_option('freetype').disabled()
|
||||
freetype_dep = dependency('', required: false)
|
||||
else
|
||||
# Sadly, FreeType's versioning schemes are different between pkg-config and CMake
|
||||
# pkg-config: freetype2, cmake: Freetype
|
||||
|
||||
# Try pkg-config name
|
||||
freetype_dep = dependency('freetype2',
|
||||
version: freetype_min_version,
|
||||
method: 'pkg-config',
|
||||
required: false,
|
||||
allow_fallback: false)
|
||||
if not freetype_dep.found()
|
||||
freetype_dep = dependency('FreeType',
|
||||
# Try cmake name
|
||||
freetype_dep = dependency('Freetype',
|
||||
version: freetype_min_version_actual,
|
||||
method: 'cmake',
|
||||
required: get_option('freetype'),
|
||||
default_options: ['harfbuzz=disabled'],
|
||||
allow_fallback: true)
|
||||
endif
|
||||
else
|
||||
# painful hack to handle multiple dependencies but also respect options
|
||||
freetype_opt = get_option('freetype')
|
||||
# we want to handle enabled manually after fallbacks, but also handle disabled normally
|
||||
if freetype_opt.enabled()
|
||||
freetype_opt = false
|
||||
endif
|
||||
# try pkg-config name
|
||||
freetype_dep = dependency('freetype2', version: freetype_min_version, method: 'pkg-config', required: freetype_opt)
|
||||
# when disabled, leave it not-found
|
||||
if not freetype_dep.found() and not get_option('freetype').disabled()
|
||||
# Try cmake name
|
||||
freetype_dep = dependency('Freetype', version: freetype_min_version_actual, method: 'cmake', required: false)
|
||||
# Subproject fallback, `allow_fallback: true` means the fallback will be
|
||||
# tried even if the freetype option is set to `auto`.
|
||||
required: false,
|
||||
allow_fallback: false)
|
||||
# Subproject fallback
|
||||
if not freetype_dep.found()
|
||||
freetype_dep = dependency('freetype2',
|
||||
version: freetype_min_version,
|
||||
method: 'pkg-config',
|
||||
freetype_proj = subproject('freetype2',
|
||||
version: freetype_min_version_actual,
|
||||
required: get_option('freetype'),
|
||||
default_options: ['harfbuzz=disabled'],
|
||||
allow_fallback: true)
|
||||
default_options: ['harfbuzz=disabled'])
|
||||
if freetype_proj.found()
|
||||
freetype_dep = freetype_proj.get_variable('freetype_dep')
|
||||
else
|
||||
freetype_dep = dependency('', required: false)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
@ -152,38 +145,12 @@ wasm_dep = cpp.find_library('iwasm', required: get_option('wasm'))
|
|||
# How to check whether iwasm was built, and hence requires, LLVM?
|
||||
#llvm_dep = cpp.find_library('LLVM-15', required: get_option('wasm'))
|
||||
|
||||
if meson.version().version_compare('>=0.60.0')
|
||||
# pkg-config: icu-uc, cmake: ICU but with components
|
||||
icu_dep = dependency('icu-uc', 'ICU',
|
||||
version: icu_min_version,
|
||||
components: 'uc',
|
||||
required: get_option('icu'),
|
||||
allow_fallback: true)
|
||||
else
|
||||
# painful hack to handle multiple dependencies but also respect options
|
||||
icu_opt = get_option('icu')
|
||||
# we want to handle enabled manually after fallbacks, but also handle disabled normally
|
||||
if icu_opt.enabled()
|
||||
icu_opt = false
|
||||
endif
|
||||
# try pkg-config name
|
||||
icu_dep = dependency('icu-uc', version: icu_min_version, method: 'pkg-config', required: icu_opt)
|
||||
# when disabled, leave it not-found
|
||||
if not icu_dep.found() and not get_option('icu').disabled()
|
||||
# Try cmake name
|
||||
icu_dep = dependency('ICU', version: icu_min_version, method: 'cmake', components: 'uc', required: false)
|
||||
# Try again with subproject fallback. `allow_fallback: true` means the
|
||||
# fallback will be tried even if the icu option is set to `auto`, but
|
||||
# we cannot pass this option until Meson 0.59.0, because no wrap file
|
||||
# is checked into git.
|
||||
if not icu_dep.found()
|
||||
icu_dep = dependency('icu-uc',
|
||||
version: icu_min_version,
|
||||
method: 'pkg-config',
|
||||
required: get_option('icu'))
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
# pkg-config: icu-uc, cmake: ICU but with components
|
||||
icu_dep = dependency('icu-uc', 'ICU',
|
||||
version: icu_min_version,
|
||||
components: 'uc',
|
||||
required: get_option('icu'),
|
||||
allow_fallback: true)
|
||||
|
||||
if icu_dep.found() and icu_dep.version().version_compare('>=75.1') and (get_option('cpp_std') == 'c++11' or get_option('cpp_std') == 'c++14')
|
||||
cpp17_arg = cpp.get_argument_syntax() == 'msvc' ? '/std:c++17' : '-std=c++17'
|
||||
|
@ -227,16 +194,18 @@ endif
|
|||
|
||||
chafa_dep = dependency('chafa', version: chafa_min_version, required: get_option('chafa'))
|
||||
|
||||
fontations_dep_found = false
|
||||
if get_option('fontations').enabled()
|
||||
add_languages(['rust'], native: false, required : true)
|
||||
fontations_dep_found = true
|
||||
endif
|
||||
|
||||
conf = configuration_data()
|
||||
incconfig = include_directories('.')
|
||||
|
||||
add_project_arguments('-DHAVE_CONFIG_H', language: ['c', 'cpp'])
|
||||
|
||||
warn_cflags = [
|
||||
'-Wno-non-virtual-dtor',
|
||||
]
|
||||
|
||||
cpp_args = cpp.get_supported_arguments(warn_cflags)
|
||||
cpp_args = []
|
||||
|
||||
if glib_dep.found()
|
||||
conf.set('HAVE_GLIB', 1)
|
||||
|
@ -272,6 +241,10 @@ if chafa_dep.found()
|
|||
conf.set('HAVE_CHAFA', 1)
|
||||
endif
|
||||
|
||||
if fontations_dep_found
|
||||
conf.set('HAVE_FONTATIONS', 1)
|
||||
endif
|
||||
|
||||
if wasm_dep.found()
|
||||
conf.set('HAVE_WASM', 1)
|
||||
conf.set('HB_WASM_MODULE_DIR', '"'+get_option('prefix')+'/'+get_option('libdir')+'/harfbuzz/wasm"')
|
||||
|
@ -315,7 +288,7 @@ endif
|
|||
gdi_uniscribe_deps = []
|
||||
# GDI (Uniscribe) (Windows)
|
||||
if host_machine.system() == 'windows' and not get_option('gdi').disabled()
|
||||
if (get_option('directwrite').enabled() and
|
||||
if (get_option('gdi').enabled() and
|
||||
not (cpp.has_header('usp10.h') and cpp.has_header('windows.h')))
|
||||
error('GDI/Uniscribe was enabled explicitly, but required headers are missing.')
|
||||
endif
|
||||
|
@ -333,13 +306,16 @@ if host_machine.system() == 'windows' and not get_option('gdi').disabled()
|
|||
endif
|
||||
endif
|
||||
|
||||
directwrite_dep = []
|
||||
# DirectWrite (Windows)
|
||||
if host_machine.system() == 'windows' and not get_option('directwrite').disabled()
|
||||
if get_option('directwrite').enabled() and not cpp.has_header('dwrite_1.h')
|
||||
if get_option('directwrite').enabled() and not cpp.has_header('dwrite_3.h')
|
||||
error('DirectWrite was enabled explicitly, but required header is missing.')
|
||||
endif
|
||||
|
||||
conf.set('HAVE_DIRECTWRITE', 1)
|
||||
directwrite_dep = cpp.find_library('dwrite', required: get_option('directwrite'))
|
||||
if directwrite_dep.found()
|
||||
conf.set('HAVE_DIRECTWRITE', 1)
|
||||
endif
|
||||
endif
|
||||
|
||||
# CoreText (macOS)
|
||||
|
@ -464,12 +440,10 @@ configure_file(output: 'config.h', configuration: conf)
|
|||
alias_target('lib', libharfbuzz)
|
||||
alias_target('libs', libharfbuzz, libharfbuzz_subset)
|
||||
|
||||
if meson.version().version_compare('>=0.57.0')
|
||||
# Re glib, see https://github.com/harfbuzz/harfbuzz/issues/4153#issuecomment-2646347531
|
||||
add_test_setup('default',
|
||||
exclude_suites: ['google-benchmark'],
|
||||
is_default: glib_dep.type_name() != 'internal' and not meson.is_subproject())
|
||||
endif
|
||||
# Re glib, see https://github.com/harfbuzz/harfbuzz/issues/4153#issuecomment-2646347531
|
||||
add_test_setup('default',
|
||||
exclude_suites: ['google-benchmark'],
|
||||
is_default: glib_dep.type_name() != 'internal' and not meson.is_subproject())
|
||||
|
||||
build_summary = {
|
||||
'Directories':
|
||||
|
|
|
@ -15,10 +15,12 @@ option('graphite2', type: 'feature', value: 'disabled',
|
|||
description: 'Enable Graphite2 complementary shaper')
|
||||
option('freetype', type: 'feature', value: 'auto',
|
||||
description: 'Enable freetype interop helpers')
|
||||
option('fontations', type: 'feature', value: 'disabled',
|
||||
description: 'Enabled fontations font functions')
|
||||
option('gdi', type: 'feature', value: 'disabled',
|
||||
description: 'Enable GDI helpers and Uniscribe shaper backend (Windows only)')
|
||||
option('directwrite', type: 'feature', value: 'disabled',
|
||||
description: 'Enable DirectWrite shaper backend on Windows (experimental)')
|
||||
description: 'Enable DirectWrite shaper backend on Windows')
|
||||
option('coretext', type: 'feature', value: 'disabled',
|
||||
description: 'Enable CoreText shaper backend on macOS')
|
||||
option('wasm', type: 'feature', value: 'disabled',
|
||||
|
|
|
@ -4,17 +4,21 @@ Benchmarks are implemented using [Google Benchmark](https://github.com/google/be
|
|||
|
||||
To build the benchmarks in this directory you need to set the benchmark
|
||||
option while configuring the build with meson:
|
||||
|
||||
```
|
||||
meson build -Dbenchmark=enabled --buildtype=release
|
||||
```
|
||||
or:
|
||||
```
|
||||
meson build -Dbenchmark=enabled --buildtype=debugoptimized
|
||||
```
|
||||
|
||||
The default build type is `debugoptimized`, which is good enough for
|
||||
benchmarking, but you can also get the fastest mode with `release`
|
||||
build type:
|
||||
```
|
||||
meson build -Dbenchmark=enabled --buildtype=release
|
||||
```
|
||||
|
||||
Then build a specific benchmark binaries with ninja:
|
||||
You should, of course, enable features you want to benchmark, like
|
||||
`-Dfreetype`, `-Dfontations`, `-Dcoretext`, etc.
|
||||
|
||||
Then build a specific benchmark binaries with ninja, eg.:
|
||||
```
|
||||
ninja -Cbuild perf/benchmark-set
|
||||
```
|
||||
|
@ -33,22 +37,47 @@ It's possible to filter the benchmarks being run and customize the output
|
|||
via flags to the benchmark binary. See the
|
||||
[Google Benchmark User Guide](https://github.com/google/benchmark/blob/main/docs/user_guide.md#user-guide) for more details.
|
||||
|
||||
The most useful benchmark is `benchmark-font`. You can provide custom fonts to it too.
|
||||
For example, to run only the "paint" benchmarks, against a given font, you can do:
|
||||
```
|
||||
./build/perf/benchmark-font NotoColorEmoji-Regular.ttf --benchmark_filter="paint"
|
||||
```
|
||||
|
||||
Some useful options are: `--benchmark_repetitions=5` to run the benchmark 5 times,
|
||||
`--benchmark_min_time=.1s` to run the benchmark for at least .1 seconds (defaults
|
||||
to .5s), and `--benchmark_filter=...` to filter the benchmarks by regular expression.
|
||||
|
||||
To compare before/after benchmarks, you need to save the benchmark results in files
|
||||
for both runs. Use `--benchmark_out=results.json` to output the results in JSON format.
|
||||
Then you can use:
|
||||
```
|
||||
./subprojects/benchmark-1.8.4/tools/compare.py benchmarks before.json after.json
|
||||
```
|
||||
Substitute your version of benchmark instead of 1.8.4.
|
||||
|
||||
# Profiling
|
||||
|
||||
Configure the build to include debug information for profiling:
|
||||
|
||||
If you like to disable optimizations and enable frame pointers for better profiling output,
|
||||
you can do so with the following meson command:
|
||||
```
|
||||
CXXFLAGS="-fno-omit-frame-pointer" meson --reconfigure build -Dbenchmark=enabled --buildtype=debug
|
||||
ninja -Cbuild
|
||||
```
|
||||
However, this will slow down the benchmarks significantly and might give you inaccurate
|
||||
information as to where to optimize. It's better to profile the `debugoptimized` build (the default).
|
||||
|
||||
Then run the benchmark with perf:
|
||||
|
||||
```
|
||||
perf record -g build/perf/benchmark-subset --benchmark_filter="BM_subset_codepoints/subset_notocjk/100000" --benchmark_repetitions=5
|
||||
```
|
||||
You probably want to filter to a specific benchmark of interest and set the number of repititions high enough to get a good sampling of profile data.
|
||||
You probably want to filter to a specific benchmark of interest and set the number of
|
||||
repititions high enough to get a good sampling of profile data.
|
||||
|
||||
Finally view the profile with:
|
||||
|
||||
```
|
||||
perf report
|
||||
```
|
||||
|
||||
Another useful `perf` tool is the `perf stat` command, which can give you a quick overview
|
||||
of the performance of a benchmark, as well as stalled cycles, cache misses, and mispredicted branches.
|
||||
|
|
|
@ -21,8 +21,6 @@ struct test_input_t
|
|||
static test_input_t *tests = default_tests;
|
||||
static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]);
|
||||
|
||||
enum backend_t { HARFBUZZ, FREETYPE, CORETEXT };
|
||||
|
||||
enum operation_t
|
||||
{
|
||||
nominal_glyphs,
|
||||
|
@ -81,7 +79,8 @@ _draw_funcs_create (void)
|
|||
}
|
||||
|
||||
static void BM_Font (benchmark::State &state,
|
||||
bool is_var, backend_t backend, operation_t operation,
|
||||
bool is_var, const char * backend,
|
||||
operation_t operation,
|
||||
const test_input_t &test_input)
|
||||
{
|
||||
hb_font_t *font;
|
||||
|
@ -100,23 +99,12 @@ static void BM_Font (benchmark::State &state,
|
|||
hb_font_set_variations (font, &wght, 1);
|
||||
}
|
||||
|
||||
switch (backend)
|
||||
bool ret = hb_font_set_funcs_using (font, backend);
|
||||
if (!ret)
|
||||
{
|
||||
case HARFBUZZ:
|
||||
hb_ot_font_set_funcs (font);
|
||||
break;
|
||||
|
||||
case FREETYPE:
|
||||
#ifdef HAVE_FREETYPE
|
||||
hb_ft_font_set_funcs (font);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case CORETEXT:
|
||||
#ifdef HAVE_CORETEXT
|
||||
hb_coretext_font_set_funcs (font);
|
||||
#endif
|
||||
break;
|
||||
state.SkipWithError("Backend failed to initialize for font.");
|
||||
hb_font_destroy (font);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (operation)
|
||||
|
@ -204,23 +192,12 @@ static void BM_Font (benchmark::State &state,
|
|||
hb_font_t *font = hb_font_create (face);
|
||||
hb_face_destroy (face);
|
||||
|
||||
switch (backend)
|
||||
bool ret = hb_font_set_funcs_using (font, backend);
|
||||
if (!ret)
|
||||
{
|
||||
case HARFBUZZ:
|
||||
hb_ot_font_set_funcs (font);
|
||||
break;
|
||||
|
||||
case FREETYPE:
|
||||
#ifdef HAVE_FREETYPE
|
||||
hb_ft_font_set_funcs (font);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case CORETEXT:
|
||||
#ifdef HAVE_CORETEXT
|
||||
hb_coretext_font_set_funcs (font);
|
||||
#endif
|
||||
break;
|
||||
state.SkipWithError("Backend failed to initialize for font.");
|
||||
hb_font_destroy (font);
|
||||
return;
|
||||
}
|
||||
|
||||
hb_buffer_t *buffer = hb_buffer_create ();
|
||||
|
@ -240,8 +217,7 @@ static void BM_Font (benchmark::State &state,
|
|||
hb_font_destroy (font);
|
||||
}
|
||||
|
||||
static void test_backend (backend_t backend,
|
||||
const char *backend_name,
|
||||
static void test_backend (const char *backend,
|
||||
bool variable,
|
||||
operation_t op,
|
||||
const char *op_name,
|
||||
|
@ -255,7 +231,7 @@ static void test_backend (backend_t backend,
|
|||
strcat (name, p ? p + 1 : test_input.font_path);
|
||||
strcat (name, variable ? "/var" : "");
|
||||
strcat (name, "/");
|
||||
strcat (name, backend_name);
|
||||
strcat (name, backend);
|
||||
|
||||
benchmark::RegisterBenchmark (name, BM_Font, variable, backend, op, test_input)
|
||||
->Unit(time_unit);
|
||||
|
@ -265,6 +241,7 @@ static void test_operation (operation_t op,
|
|||
const char *op_name,
|
||||
benchmark::TimeUnit time_unit)
|
||||
{
|
||||
const char **supported_backends = hb_font_list_funcs ();
|
||||
for (unsigned i = 0; i < num_tests; i++)
|
||||
{
|
||||
auto& test_input = tests[i];
|
||||
|
@ -272,13 +249,8 @@ static void test_operation (operation_t op,
|
|||
{
|
||||
bool is_var = (bool) variable;
|
||||
|
||||
test_backend (HARFBUZZ, "hb", is_var, op, op_name, time_unit, test_input);
|
||||
#ifdef HAVE_FREETYPE
|
||||
test_backend (FREETYPE, "ft", is_var, op, op_name, time_unit, test_input);
|
||||
#endif
|
||||
#ifdef HAVE_CORETEXT
|
||||
test_backend (CORETEXT, "coretext", is_var, op, op_name, time_unit, test_input);
|
||||
#endif
|
||||
for (const char **backend = supported_backends; *backend; backend++)
|
||||
test_backend (*backend, is_var, op, op_name, time_unit, test_input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ struct test_input_t
|
|||
|
||||
static test_input_t *tests = default_tests;
|
||||
static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]);
|
||||
const char *variation = nullptr;
|
||||
|
||||
static void BM_Shape (benchmark::State &state,
|
||||
const char *shaper,
|
||||
|
@ -46,6 +47,13 @@ static void BM_Shape (benchmark::State &state,
|
|||
hb_face_destroy (face);
|
||||
}
|
||||
|
||||
if (variation)
|
||||
{
|
||||
hb_variation_t var;
|
||||
hb_variation_from_string (variation, -1, &var);
|
||||
hb_font_set_variations (font, &var, 1);
|
||||
}
|
||||
|
||||
hb_blob_t *text_blob = hb_blob_create_from_file_or_fail (input.text_path);
|
||||
assert (text_blob);
|
||||
unsigned orig_text_length;
|
||||
|
@ -99,16 +107,16 @@ int main(int argc, char** argv)
|
|||
{
|
||||
benchmark::Initialize(&argc, argv);
|
||||
|
||||
test_input_t static_test = {};
|
||||
if (argc > 2)
|
||||
{
|
||||
num_tests = (argc - 1) / 2;
|
||||
tests = (test_input_t *) calloc (num_tests, sizeof (test_input_t));
|
||||
for (unsigned i = 0; i < num_tests; i++)
|
||||
{
|
||||
tests[i].font_path = argv[1 + i * 2];
|
||||
tests[i].text_path = argv[2 + i * 2];
|
||||
}
|
||||
static_test.font_path = argv[1];
|
||||
static_test.text_path = argv[2];
|
||||
tests = &static_test;
|
||||
num_tests = 1;
|
||||
}
|
||||
if (argc > 3)
|
||||
variation = argv[3];
|
||||
|
||||
for (unsigned i = 0; i < num_tests; i++)
|
||||
{
|
||||
|
@ -120,7 +128,4 @@ int main(int argc, char** argv)
|
|||
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
benchmark::Shutdown();
|
||||
|
||||
if (tests != default_tests)
|
||||
free (tests);
|
||||
}
|
||||
|
|
|
@ -36,6 +36,9 @@
|
|||
#ifdef HAVE_FREETYPE
|
||||
#include <hb-ft.h>
|
||||
#endif
|
||||
#ifdef HAVE_FONTATIONS
|
||||
#include <hb-fontations.h>
|
||||
#endif
|
||||
#ifdef HAVE_CORETEXT
|
||||
#include <hb-coretext.h>
|
||||
#endif
|
||||
|
@ -53,22 +56,7 @@ static inline hb_face_t *
|
|||
hb_benchmark_face_create_from_file_or_fail (const char *font_path,
|
||||
unsigned face_index)
|
||||
{
|
||||
const char *loader = getenv ("HB_FACE_LOADER");
|
||||
if (loader && !*loader)
|
||||
loader = nullptr;
|
||||
|
||||
#ifdef HAVE_FREETYPE
|
||||
if (loader && !strcmp (loader, "ft"))
|
||||
return hb_ft_face_create_from_file_or_fail (font_path, face_index);
|
||||
#endif
|
||||
#ifdef HAVE_CORETEXT
|
||||
if (loader && !strcmp (loader, "coretext"))
|
||||
return hb_coretext_face_create_from_file_or_fail (font_path, face_index);
|
||||
#endif
|
||||
if (!loader || !strcmp (loader, "ot"))
|
||||
return hb_face_create_from_file_or_fail (font_path, face_index);
|
||||
|
||||
assert (false);
|
||||
return hb_face_create_from_file_or_fail_using (font_path, face_index, nullptr);
|
||||
}
|
||||
|
||||
HB_END_DECLS
|
||||
|
|
45
perf/hb-draw-all.c
Normal file
45
perf/hb-draw-all.c
Normal file
|
@ -0,0 +1,45 @@
|
|||
#include <hb.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
fprintf (stderr, "Usage: %s font-file [font-funcs] [wght]\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
hb_face_t *face = hb_face_create_from_file_or_fail (argv[1], 0);
|
||||
|
||||
if (!face)
|
||||
{
|
||||
fprintf (stderr, "Failed to create face\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
hb_font_t *font = hb_font_create (face);
|
||||
|
||||
if (argc > 2)
|
||||
hb_font_set_funcs_using (font, argv[2]);
|
||||
|
||||
if (argc > 3)
|
||||
{
|
||||
hb_variation_t variations[] = {
|
||||
{ HB_TAG ('w', 'g', 'h', 't'), atoi (argv[3]) },
|
||||
};
|
||||
hb_font_set_variations (font, variations, 1);
|
||||
}
|
||||
|
||||
hb_draw_funcs_t *funcs = hb_draw_funcs_create ();
|
||||
|
||||
unsigned glyph_count = hb_face_get_glyph_count (face);
|
||||
for (unsigned gid = 0; gid < glyph_count; gid++)
|
||||
hb_font_draw_glyph (font, gid, funcs, NULL);
|
||||
|
||||
hb_draw_funcs_destroy (funcs);
|
||||
hb_font_destroy (font);
|
||||
hb_face_destroy (face);
|
||||
return 0;
|
||||
}
|
45
perf/hb-paint-all.c
Normal file
45
perf/hb-paint-all.c
Normal file
|
@ -0,0 +1,45 @@
|
|||
#include <hb.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
fprintf (stderr, "Usage: %s font-file [font-funcs] [wght]\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
hb_face_t *face = hb_face_create_from_file_or_fail (argv[1], 0);
|
||||
|
||||
if (!face)
|
||||
{
|
||||
fprintf (stderr, "Failed to create face\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
hb_font_t *font = hb_font_create (face);
|
||||
|
||||
if (argc > 2)
|
||||
hb_font_set_funcs_using (font, argv[2]);
|
||||
|
||||
if (argc > 3)
|
||||
{
|
||||
hb_variation_t variations[] = {
|
||||
{ HB_TAG ('w', 'g', 'h', 't'), atoi (argv[3]) },
|
||||
};
|
||||
hb_font_set_variations (font, variations, 1);
|
||||
}
|
||||
|
||||
hb_paint_funcs_t *funcs = hb_paint_funcs_create ();
|
||||
|
||||
unsigned glyph_count = hb_face_get_glyph_count (face);
|
||||
for (unsigned gid = 0; gid < glyph_count; gid++)
|
||||
hb_font_paint_glyph (font, gid, funcs, NULL, 0, 0);
|
||||
|
||||
hb_paint_funcs_destroy (funcs);
|
||||
hb_font_destroy (font);
|
||||
hb_face_destroy (face);
|
||||
return 0;
|
||||
}
|
|
@ -38,3 +38,17 @@ foreach source : benchmarks_subset
|
|||
install: false,
|
||||
), workdir: meson.current_source_dir() / '..', timeout: 100)
|
||||
endforeach
|
||||
|
||||
hb_draw_all = executable('hb-draw-all', ['hb-draw-all.c'],
|
||||
cpp_args: cpp_args,
|
||||
include_directories: [incconfig, incsrc],
|
||||
link_with: [libharfbuzz],
|
||||
)
|
||||
meson.override_find_program('hb-draw-all', hb_draw_all)
|
||||
|
||||
hb_paint_all = executable('hb-paint-all', ['hb-paint-all.c'],
|
||||
cpp_args: cpp_args,
|
||||
include_directories: [incconfig, incsrc],
|
||||
link_with: [libharfbuzz],
|
||||
)
|
||||
meson.override_find_program('hb-paint-all', hb_paint_all)
|
||||
|
|
|
@ -941,10 +941,12 @@ struct CBDT
|
|||
}
|
||||
}
|
||||
|
||||
bool has_data () const { return cbdt.get_length (); }
|
||||
bool has_data () const { return cbdt->version.major; }
|
||||
|
||||
bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data) const
|
||||
{
|
||||
if (!has_data ()) return false;
|
||||
|
||||
hb_glyph_extents_t extents;
|
||||
hb_glyph_extents_t pixel_extents;
|
||||
hb_blob_t *blob = reference_png (font, glyph);
|
||||
|
|
|
@ -47,6 +47,11 @@ namespace OT {
|
|||
struct hb_paint_context_t;
|
||||
}
|
||||
|
||||
struct hb_colr_scratch_t
|
||||
{
|
||||
hb_paint_extents_context_t paint_extents;
|
||||
};
|
||||
|
||||
namespace OT {
|
||||
|
||||
struct COLR;
|
||||
|
@ -90,7 +95,8 @@ public:
|
|||
font (font_),
|
||||
palette (
|
||||
#ifndef HB_NO_COLOR
|
||||
font->face->table.CPAL->get_palette_colors (palette_)
|
||||
// https://github.com/harfbuzz/harfbuzz/issues/5116
|
||||
font->face->table.CPAL->get_palette_colors (palette_ < font->face->table.CPAL->get_palette_count () ? palette_ : 0)
|
||||
#endif
|
||||
),
|
||||
foreground (foreground_),
|
||||
|
@ -932,9 +938,9 @@ struct PaintGlyph
|
|||
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_inverse_font_transform (c->data, c->font);
|
||||
c->funcs->push_clip_glyph (c->data, gid, c->font);
|
||||
c->funcs->push_root_transform (c->data, c->font);
|
||||
c->funcs->push_font_transform (c->data, c->font);
|
||||
c->recurse (this+paint);
|
||||
c->funcs->pop_transform (c->data);
|
||||
c->funcs->pop_clip (c->data);
|
||||
|
@ -1511,10 +1517,12 @@ struct PaintComposite
|
|||
void paint_glyph (hb_paint_context_t *c) const
|
||||
{
|
||||
TRACE_PAINT (this);
|
||||
c->funcs->push_group (c->data);
|
||||
c->recurse (this+backdrop);
|
||||
c->funcs->push_group (c->data);
|
||||
c->recurse (this+src);
|
||||
c->funcs->pop_group (c->data, (hb_paint_composite_mode_t) (int) mode);
|
||||
c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
|
||||
}
|
||||
|
||||
HBUINT8 format; /* format = 32 */
|
||||
|
@ -2079,6 +2087,8 @@ struct COLR
|
|||
{
|
||||
static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR;
|
||||
|
||||
bool has_data () const { return has_v0_data () || version; }
|
||||
|
||||
bool has_v0_data () const { return numBaseGlyphs; }
|
||||
bool has_v1_data () const
|
||||
{
|
||||
|
@ -2112,7 +2122,53 @@ struct COLR
|
|||
{
|
||||
accelerator_t (hb_face_t *face)
|
||||
{ colr = hb_sanitize_context_t ().reference_table<COLR> (face); }
|
||||
~accelerator_t () { this->colr.destroy (); }
|
||||
|
||||
~accelerator_t ()
|
||||
{
|
||||
auto *scratch = cached_scratch.get_relaxed ();
|
||||
if (scratch)
|
||||
{
|
||||
scratch->~hb_colr_scratch_t ();
|
||||
hb_free (scratch);
|
||||
}
|
||||
|
||||
colr.destroy ();
|
||||
}
|
||||
|
||||
|
||||
bool has_data () const { return colr->has_data (); }
|
||||
|
||||
#ifndef HB_NO_PAINT
|
||||
bool
|
||||
get_extents (hb_font_t *font,
|
||||
hb_codepoint_t glyph,
|
||||
hb_glyph_extents_t *extents) const
|
||||
{
|
||||
if (unlikely (!has_data ())) return false;
|
||||
|
||||
hb_colr_scratch_t *scratch = acquire_scratch ();
|
||||
if (unlikely (!scratch)) return true;
|
||||
bool ret = colr->get_extents (font, glyph, extents, *scratch);
|
||||
release_scratch (scratch);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool paint_glyph (hb_font_t *font,
|
||||
hb_codepoint_t glyph,
|
||||
hb_paint_funcs_t *funcs, void *data,
|
||||
unsigned int palette_index,
|
||||
hb_color_t foreground,
|
||||
bool clip = true) const
|
||||
{
|
||||
if (unlikely (!has_data ())) return false;
|
||||
|
||||
hb_colr_scratch_t *scratch = acquire_scratch ();
|
||||
if (unlikely (!scratch)) return true;
|
||||
bool ret = colr->paint_glyph (font, glyph, funcs, data, palette_index, foreground, clip, *scratch);
|
||||
release_scratch (scratch);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool is_valid () { return colr.get_blob ()->length; }
|
||||
|
||||
|
@ -2148,7 +2204,33 @@ struct COLR
|
|||
{ return colr->get_delta_set_index_map_ptr (); }
|
||||
|
||||
private:
|
||||
|
||||
hb_colr_scratch_t *acquire_scratch () const
|
||||
{
|
||||
hb_colr_scratch_t *scratch = cached_scratch.get_acquire ();
|
||||
|
||||
if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr)))
|
||||
{
|
||||
scratch = (hb_colr_scratch_t *) hb_calloc (1, sizeof (hb_colr_scratch_t));
|
||||
if (unlikely (!scratch))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return scratch;
|
||||
}
|
||||
void release_scratch (hb_colr_scratch_t *scratch) const
|
||||
{
|
||||
if (!cached_scratch.cmpexch (nullptr, scratch))
|
||||
{
|
||||
scratch->~hb_colr_scratch_t ();
|
||||
hb_free (scratch);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
hb_blob_ptr_t<COLR> colr;
|
||||
private:
|
||||
hb_atomic_t<hb_colr_scratch_t *> cached_scratch;
|
||||
};
|
||||
|
||||
void closure_glyphs (hb_codepoint_t glyph,
|
||||
|
@ -2520,7 +2602,10 @@ struct COLR
|
|||
|
||||
#ifndef HB_NO_PAINT
|
||||
bool
|
||||
get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
|
||||
get_extents (hb_font_t *font,
|
||||
hb_codepoint_t glyph,
|
||||
hb_glyph_extents_t *extents,
|
||||
hb_colr_scratch_t &scratch) const
|
||||
{
|
||||
|
||||
ItemVarStoreInstancer instancer (get_var_store_ptr (),
|
||||
|
@ -2534,10 +2619,10 @@ struct COLR
|
|||
}
|
||||
|
||||
auto *extents_funcs = hb_paint_extents_get_funcs ();
|
||||
hb_paint_extents_context_t extents_data;
|
||||
bool ret = paint_glyph (font, glyph, extents_funcs, &extents_data, 0, HB_COLOR(0,0,0,0));
|
||||
scratch.paint_extents.clear ();
|
||||
bool ret = paint_glyph (font, glyph, extents_funcs, &scratch.paint_extents, 0, HB_COLOR(0,0,0,0), true, scratch);
|
||||
|
||||
hb_extents_t e = extents_data.get_extents ();
|
||||
auto e = scratch.paint_extents.get_extents ();
|
||||
if (e.is_void ())
|
||||
{
|
||||
extents->x_bearing = 0;
|
||||
|
@ -2547,6 +2632,7 @@ struct COLR
|
|||
}
|
||||
else
|
||||
{
|
||||
// Ugh. We need to undo the synthetic slant here. Leave it for now. :-(.
|
||||
extents->x_bearing = e.xmin;
|
||||
extents->y_bearing = e.ymax;
|
||||
extents->width = e.xmax - e.xmin;
|
||||
|
@ -2583,7 +2669,12 @@ struct COLR
|
|||
|
||||
#ifndef HB_NO_PAINT
|
||||
bool
|
||||
paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, unsigned int palette_index, hb_color_t foreground, bool clip = true) const
|
||||
paint_glyph (hb_font_t *font,
|
||||
hb_codepoint_t glyph,
|
||||
hb_paint_funcs_t *funcs, void *data,
|
||||
unsigned int palette_index, hb_color_t foreground,
|
||||
bool clip,
|
||||
hb_colr_scratch_t &scratch) const
|
||||
{
|
||||
ItemVarStoreInstancer instancer (get_var_store_ptr (),
|
||||
get_delta_set_index_map_ptr (),
|
||||
|
@ -2609,6 +2700,7 @@ struct COLR
|
|||
if (get_clip (glyph, &extents, instancer))
|
||||
{
|
||||
font->scale_glyph_extents (&extents);
|
||||
font->synthetic_glyph_extents (&extents);
|
||||
c.funcs->push_clip_rectangle (c.data,
|
||||
extents.x_bearing,
|
||||
extents.y_bearing + extents.height,
|
||||
|
@ -2618,15 +2710,16 @@ struct COLR
|
|||
else
|
||||
{
|
||||
auto *extents_funcs = hb_paint_extents_get_funcs ();
|
||||
hb_paint_extents_context_t extents_data;
|
||||
scratch.paint_extents.clear ();
|
||||
|
||||
paint_glyph (font, glyph,
|
||||
extents_funcs, &extents_data,
|
||||
extents_funcs, &scratch.paint_extents,
|
||||
palette_index, foreground,
|
||||
false);
|
||||
false,
|
||||
scratch);
|
||||
|
||||
hb_extents_t extents = extents_data.get_extents ();
|
||||
is_bounded = extents_data.is_bounded ();
|
||||
auto extents = scratch.paint_extents.get_extents ();
|
||||
is_bounded = scratch.paint_extents.is_bounded ();
|
||||
|
||||
c.funcs->push_clip_rectangle (c.data,
|
||||
extents.xmin,
|
||||
|
@ -2636,7 +2729,7 @@ struct COLR
|
|||
}
|
||||
}
|
||||
|
||||
c.funcs->push_root_transform (c.data, font);
|
||||
c.funcs->push_font_transform (c.data, font);
|
||||
|
||||
if (is_bounded)
|
||||
c.recurse (*paint);
|
||||
|
@ -2714,9 +2807,7 @@ void PaintColrLayers::paint_glyph (hb_paint_context_t *c) const
|
|||
return;
|
||||
|
||||
const Paint &paint = paint_offset_lists.get_paint (i);
|
||||
c->funcs->push_group (c->data);
|
||||
c->recurse (paint);
|
||||
c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2728,7 +2819,7 @@ void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const
|
|||
if (unlikely (!node.visit (gid)))
|
||||
return;
|
||||
|
||||
c->funcs->push_inverse_root_transform (c->data, c->font);
|
||||
c->funcs->push_inverse_font_transform (c->data, c->font);
|
||||
if (c->funcs->color_glyph (c->data, gid, c->font))
|
||||
{
|
||||
c->funcs->pop_transform (c->data);
|
||||
|
|
|
@ -77,7 +77,7 @@ struct CoverageFormat1_3
|
|||
|
||||
bool intersects (const hb_set_t *glyphs) const
|
||||
{
|
||||
if (glyphArray.len > glyphs->get_population () * hb_bit_storage ((unsigned) glyphArray.len) / 2)
|
||||
if (glyphArray.len > glyphs->get_population () * hb_bit_storage ((unsigned) glyphArray.len))
|
||||
{
|
||||
for (auto g : *glyphs)
|
||||
if (get_coverage (g) != NOT_COVERED)
|
||||
|
|
|
@ -120,7 +120,7 @@ struct CoverageFormat2_4
|
|||
|
||||
bool intersects (const hb_set_t *glyphs) const
|
||||
{
|
||||
if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2)
|
||||
if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len))
|
||||
{
|
||||
for (auto g : *glyphs)
|
||||
if (get_coverage (g) != NOT_COVERED)
|
||||
|
|
|
@ -205,20 +205,19 @@ struct CaretValueFormat3
|
|||
|
||||
unsigned varidx = (this+deviceTable).get_variation_index ();
|
||||
hb_pair_t<unsigned, int> *new_varidx_delta;
|
||||
if (!c->plan->layout_variation_idx_delta_map.has (varidx, &new_varidx_delta))
|
||||
return_trace (false);
|
||||
if (c->plan->layout_variation_idx_delta_map.has (varidx, &new_varidx_delta)) {
|
||||
uint32_t new_varidx = hb_first (*new_varidx_delta);
|
||||
int delta = hb_second (*new_varidx_delta);
|
||||
if (delta != 0)
|
||||
{
|
||||
if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW))
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
uint32_t new_varidx = hb_first (*new_varidx_delta);
|
||||
int delta = hb_second (*new_varidx_delta);
|
||||
if (delta != 0)
|
||||
{
|
||||
if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW))
|
||||
return_trace (false);
|
||||
if (new_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
|
||||
return_trace (c->serializer->check_assign (out->caretValueFormat, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW));
|
||||
}
|
||||
|
||||
if (new_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
|
||||
return_trace (c->serializer->check_assign (out->caretValueFormat, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW));
|
||||
|
||||
if (!c->serializer->embed (deviceTable))
|
||||
return_trace (false);
|
||||
|
||||
|
@ -1015,7 +1014,8 @@ struct GDEF
|
|||
hb_blob_ptr_t<GDEF> table;
|
||||
#ifndef HB_NO_GDEF_CACHE
|
||||
hb_vector_t<hb_set_digest_t> mark_glyph_set_digests;
|
||||
mutable hb_cache_t<21, 3, 8> glyph_props_cache;
|
||||
mutable hb_cache_t<21, 3> glyph_props_cache;
|
||||
static_assert (sizeof (glyph_props_cache) == 512, "");
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ struct PairPosFormat1_3
|
|||
{
|
||||
auto &cov = this+coverage;
|
||||
|
||||
if (pairSet.len > glyphs->get_population () * hb_bit_storage ((unsigned) pairSet.len) / 4)
|
||||
if (pairSet.len > glyphs->get_population () * hb_bit_storage ((unsigned) pairSet.len))
|
||||
{
|
||||
for (hb_codepoint_t g : glyphs->iter())
|
||||
{
|
||||
|
|
|
@ -126,25 +126,19 @@ hb_transforming_pen_get_funcs ()
|
|||
return static_transforming_pen_funcs.get_unconst ();
|
||||
}
|
||||
|
||||
|
||||
hb_ubytes_t
|
||||
VarComponent::get_path_at (hb_font_t *font,
|
||||
VarComponent::get_path_at (const hb_varc_context_t &c,
|
||||
hb_codepoint_t parent_gid,
|
||||
hb_draw_session_t &draw_session,
|
||||
hb_array_t<const int> coords,
|
||||
hb_transform_t total_transform,
|
||||
hb_ubytes_t total_record,
|
||||
hb_decycler_t *decycler,
|
||||
signed *edges_left,
|
||||
signed depth_left,
|
||||
VarRegionList::cache_t *cache) const
|
||||
{
|
||||
const unsigned char *end = total_record.arrayZ + total_record.length;
|
||||
const unsigned char *record = total_record.arrayZ;
|
||||
|
||||
auto &VARC = *font->face->table.VARC;
|
||||
auto &VARC = *c.font->face->table.VARC->table;
|
||||
auto &varStore = &VARC+VARC.varStore;
|
||||
auto instancer = MultiItemVarStoreInstancer(&varStore, nullptr, coords, cache);
|
||||
|
||||
#define READ_UINT32VAR(name) \
|
||||
HB_STMT_START { \
|
||||
|
@ -187,22 +181,25 @@ VarComponent::get_path_at (hb_font_t *font,
|
|||
unsigned conditionIndex;
|
||||
READ_UINT32VAR (conditionIndex);
|
||||
const auto &condition = (&VARC+VARC.conditionList)[conditionIndex];
|
||||
auto instancer = MultiItemVarStoreInstancer(&varStore, nullptr, coords, cache);
|
||||
show = condition.evaluate (coords.arrayZ, coords.length, &instancer);
|
||||
}
|
||||
|
||||
// Axis values
|
||||
|
||||
hb_vector_t<unsigned> axisIndices;
|
||||
hb_vector_t<float> axisValues;
|
||||
auto &axisIndices = c.scratch.axisIndices;
|
||||
axisIndices.clear ();
|
||||
auto &axisValues = c.scratch.axisValues;
|
||||
axisValues.clear ();
|
||||
if (flags & (unsigned) flags_t::HAVE_AXES)
|
||||
{
|
||||
unsigned axisIndicesIndex;
|
||||
READ_UINT32VAR (axisIndicesIndex);
|
||||
axisIndices = (&VARC+VARC.axisIndicesList)[axisIndicesIndex];
|
||||
axisIndices.extend ((&VARC+VARC.axisIndicesList)[axisIndicesIndex]);
|
||||
axisValues.resize (axisIndices.length);
|
||||
const HBUINT8 *p = (const HBUINT8 *) record;
|
||||
TupleValues::decompile (p, axisValues, (const HBUINT8 *) end);
|
||||
record += (const unsigned char *) p - record;
|
||||
record = (const unsigned char *) p;
|
||||
}
|
||||
|
||||
// Apply variations if any
|
||||
|
@ -219,7 +216,7 @@ VarComponent::get_path_at (hb_font_t *font,
|
|||
* limit on the max number of coords for now. */
|
||||
if ((flags & (unsigned) flags_t::RESET_UNSPECIFIED_AXES) ||
|
||||
coords.length > HB_VAR_COMPOSITE_MAX_AXES)
|
||||
component_coords = hb_array<int> (font->coords, font->num_coords);
|
||||
component_coords = hb_array<int> (c.font->coords, c.font->num_coords);
|
||||
|
||||
// Transform
|
||||
|
||||
|
@ -313,13 +310,18 @@ VarComponent::get_path_at (hb_font_t *font,
|
|||
transform.scaleY = transform.scaleX;
|
||||
|
||||
total_transform.transform (transform.to_transform ());
|
||||
total_transform.scale (font->x_mult ? 1.f / font->x_multf : 0.f,
|
||||
font->y_mult ? 1.f / font->y_multf : 0.f);
|
||||
total_transform.scale (c.font->x_mult ? 1.f / c.font->x_multf : 0.f,
|
||||
c.font->y_mult ? 1.f / c.font->y_multf : 0.f);
|
||||
|
||||
VARC.get_path_at (font, gid,
|
||||
draw_session, component_coords, total_transform,
|
||||
bool same_coords = component_coords.length == coords.length &&
|
||||
component_coords.arrayZ == coords.arrayZ;
|
||||
|
||||
c.depth_left--;
|
||||
VARC.get_path_at (c, gid,
|
||||
component_coords, total_transform,
|
||||
parent_gid,
|
||||
decycler, edges_left, depth_left - 1);
|
||||
same_coords ? cache : nullptr);
|
||||
c.depth_left++;
|
||||
}
|
||||
|
||||
#undef PROCESS_TRANSFORM_COMPONENTS
|
||||
|
@ -329,15 +331,12 @@ VarComponent::get_path_at (hb_font_t *font,
|
|||
}
|
||||
|
||||
bool
|
||||
VARC::get_path_at (hb_font_t *font,
|
||||
VARC::get_path_at (const hb_varc_context_t &c,
|
||||
hb_codepoint_t glyph,
|
||||
hb_draw_session_t &draw_session,
|
||||
hb_array_t<const int> coords,
|
||||
hb_transform_t transform,
|
||||
hb_codepoint_t parent_glyph,
|
||||
hb_decycler_t *decycler,
|
||||
signed *edges_left,
|
||||
signed depth_left) const
|
||||
VarRegionList::cache_t *parent_cache) const
|
||||
{
|
||||
// Don't recurse on the same glyph.
|
||||
unsigned idx = glyph == parent_glyph ?
|
||||
|
@ -345,50 +344,69 @@ VARC::get_path_at (hb_font_t *font,
|
|||
(this+coverage).get_coverage (glyph);
|
||||
if (idx == NOT_COVERED)
|
||||
{
|
||||
// Build a transforming pen to apply the transform.
|
||||
hb_draw_funcs_t *transformer_funcs = hb_transforming_pen_get_funcs ();
|
||||
hb_transforming_pen_context_t context {transform,
|
||||
draw_session.funcs,
|
||||
draw_session.draw_data,
|
||||
&draw_session.st};
|
||||
hb_draw_session_t transformer_session {transformer_funcs, &context};
|
||||
hb_draw_session_t &shape_draw_session = transform.is_identity () ? draw_session : transformer_session;
|
||||
if (c.draw_session)
|
||||
{
|
||||
// Build a transforming pen to apply the transform.
|
||||
hb_draw_funcs_t *transformer_funcs = hb_transforming_pen_get_funcs ();
|
||||
hb_transforming_pen_context_t context {transform,
|
||||
c.draw_session->funcs,
|
||||
c.draw_session->draw_data,
|
||||
&c.draw_session->st};
|
||||
hb_draw_session_t transformer_session {transformer_funcs, &context};
|
||||
hb_draw_session_t &shape_draw_session = transform.is_identity () ? *c.draw_session : transformer_session;
|
||||
|
||||
if (!font->face->table.glyf->get_path_at (font, glyph, shape_draw_session, coords))
|
||||
if (!c.font->face->table.glyf->get_path_at (c.font, glyph, shape_draw_session, coords, c.scratch.glyf_scratch))
|
||||
#ifndef HB_NO_CFF
|
||||
if (!font->face->table.cff2->get_path_at (font, glyph, shape_draw_session, coords))
|
||||
if (!font->face->table.cff1->get_path (font, glyph, shape_draw_session)) // Doesn't have variations
|
||||
if (!c.font->face->table.cff2->get_path_at (c.font, glyph, shape_draw_session, coords))
|
||||
if (!c.font->face->table.cff1->get_path (c.font, glyph, shape_draw_session)) // Doesn't have variations
|
||||
#endif
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
else if (c.extents)
|
||||
{
|
||||
hb_glyph_extents_t glyph_extents;
|
||||
if (!c.font->face->table.glyf->get_extents_at (c.font, glyph, &glyph_extents, coords))
|
||||
#ifndef HB_NO_CFF
|
||||
if (!c.font->face->table.cff2->get_extents_at (c.font, glyph, &glyph_extents, coords))
|
||||
if (!c.font->face->table.cff1->get_extents (c.font, glyph, &glyph_extents)) // Doesn't have variations
|
||||
#endif
|
||||
return false;
|
||||
|
||||
hb_extents_t comp_extents (glyph_extents);
|
||||
transform.transform_extents (comp_extents);
|
||||
c.extents->union_ (comp_extents);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (depth_left <= 0)
|
||||
if (c.depth_left <= 0)
|
||||
return true;
|
||||
|
||||
if (*edges_left <= 0)
|
||||
if (c.edges_left <= 0)
|
||||
return true;
|
||||
(*edges_left)--;
|
||||
(c.edges_left)--;
|
||||
|
||||
hb_decycler_node_t node (*decycler);
|
||||
hb_decycler_node_t node (c.decycler);
|
||||
if (unlikely (!node.visit (glyph)))
|
||||
return true;
|
||||
|
||||
hb_ubytes_t record = (this+glyphRecords)[idx];
|
||||
|
||||
VarRegionList::cache_t *cache = record.length >= 64 ? // Heuristic
|
||||
(this+varStore).create_cache ()
|
||||
: nullptr;
|
||||
VarRegionList::cache_t static_cache[sizeof (void *) * 16];
|
||||
VarRegionList::cache_t *cache = parent_cache ?
|
||||
parent_cache :
|
||||
(this+varStore).create_cache (hb_array (static_cache));
|
||||
|
||||
transform.scale (font->x_multf, font->y_multf);
|
||||
transform.scale (c.font->x_multf, c.font->y_multf);
|
||||
|
||||
VarCompositeGlyph::get_path_at (font, glyph,
|
||||
draw_session, coords, transform,
|
||||
VarCompositeGlyph::get_path_at (c,
|
||||
glyph,
|
||||
coords, transform,
|
||||
record,
|
||||
decycler, edges_left, depth_left,
|
||||
cache);
|
||||
|
||||
(this+varStore).destroy_cache (cache);
|
||||
if (cache != parent_cache)
|
||||
(this+varStore).destroy_cache (cache, hb_array (static_cache));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,24 @@ namespace OT {
|
|||
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
|
||||
struct hb_varc_scratch_t
|
||||
{
|
||||
hb_vector_t<unsigned> axisIndices;
|
||||
hb_vector_t<float> axisValues;
|
||||
hb_glyf_scratch_t glyf_scratch;
|
||||
};
|
||||
|
||||
struct hb_varc_context_t
|
||||
{
|
||||
hb_font_t *font;
|
||||
hb_draw_session_t *draw_session;
|
||||
hb_extents_t *extents;
|
||||
mutable hb_decycler_t decycler;
|
||||
mutable signed edges_left;
|
||||
mutable signed depth_left;
|
||||
hb_varc_scratch_t &scratch;
|
||||
};
|
||||
|
||||
struct VarComponent
|
||||
{
|
||||
enum class flags_t : uint32_t
|
||||
|
@ -44,39 +62,32 @@ struct VarComponent
|
|||
};
|
||||
|
||||
HB_INTERNAL hb_ubytes_t
|
||||
get_path_at (hb_font_t *font,
|
||||
get_path_at (const hb_varc_context_t &c,
|
||||
hb_codepoint_t parent_gid,
|
||||
hb_draw_session_t &draw_session,
|
||||
hb_array_t<const int> coords,
|
||||
hb_transform_t transform,
|
||||
hb_ubytes_t record,
|
||||
hb_decycler_t *decycler,
|
||||
signed *edges_left,
|
||||
signed depth_left,
|
||||
VarRegionList::cache_t *cache = nullptr) const;
|
||||
};
|
||||
|
||||
struct VarCompositeGlyph
|
||||
{
|
||||
static void
|
||||
get_path_at (hb_font_t *font,
|
||||
hb_codepoint_t glyph,
|
||||
hb_draw_session_t &draw_session,
|
||||
get_path_at (const hb_varc_context_t &c,
|
||||
hb_codepoint_t gid,
|
||||
hb_array_t<const int> coords,
|
||||
hb_transform_t transform,
|
||||
hb_ubytes_t record,
|
||||
hb_decycler_t *decycler,
|
||||
signed *edges_left,
|
||||
signed depth_left,
|
||||
VarRegionList::cache_t *cache = nullptr)
|
||||
VarRegionList::cache_t *cache)
|
||||
{
|
||||
while (record)
|
||||
{
|
||||
const VarComponent &comp = * (const VarComponent *) (record.arrayZ);
|
||||
record = comp.get_path_at (font, glyph,
|
||||
draw_session, coords, transform,
|
||||
record = comp.get_path_at (c,
|
||||
gid,
|
||||
coords, transform,
|
||||
record,
|
||||
decycler, edges_left, depth_left, cache);
|
||||
cache);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -90,31 +101,48 @@ struct VARC
|
|||
static constexpr hb_tag_t tableTag = HB_TAG ('V', 'A', 'R', 'C');
|
||||
|
||||
HB_INTERNAL bool
|
||||
get_path_at (hb_font_t *font,
|
||||
hb_codepoint_t glyph,
|
||||
hb_draw_session_t &draw_session,
|
||||
get_path_at (const hb_varc_context_t &c,
|
||||
hb_codepoint_t gid,
|
||||
hb_array_t<const int> coords,
|
||||
hb_transform_t transform,
|
||||
hb_codepoint_t parent_glyph,
|
||||
hb_decycler_t *decycler,
|
||||
signed *edges_left,
|
||||
signed depth_left) const;
|
||||
hb_transform_t transform = HB_TRANSFORM_IDENTITY,
|
||||
hb_codepoint_t parent_gid = HB_CODEPOINT_INVALID,
|
||||
VarRegionList::cache_t *parent_cache = nullptr) const;
|
||||
|
||||
bool
|
||||
get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const
|
||||
get_path (hb_font_t *font,
|
||||
hb_codepoint_t gid,
|
||||
hb_draw_session_t &draw_session,
|
||||
hb_varc_scratch_t &scratch) const
|
||||
{
|
||||
hb_decycler_t decycler;
|
||||
signed edges = HB_MAX_GRAPH_EDGE_COUNT;
|
||||
hb_varc_context_t c {font,
|
||||
&draw_session,
|
||||
nullptr,
|
||||
hb_decycler_t {},
|
||||
HB_MAX_GRAPH_EDGE_COUNT,
|
||||
HB_MAX_NESTING_LEVEL,
|
||||
scratch};
|
||||
|
||||
return get_path_at (font,
|
||||
gid,
|
||||
draw_session,
|
||||
hb_array (font->coords, font->num_coords),
|
||||
HB_TRANSFORM_IDENTITY,
|
||||
HB_CODEPOINT_INVALID,
|
||||
&decycler,
|
||||
&edges,
|
||||
HB_MAX_NESTING_LEVEL); }
|
||||
return get_path_at (c, gid,
|
||||
hb_array (font->coords, font->num_coords));
|
||||
}
|
||||
|
||||
bool
|
||||
get_extents (hb_font_t *font,
|
||||
hb_codepoint_t gid,
|
||||
hb_extents_t *extents,
|
||||
hb_varc_scratch_t &scratch) const
|
||||
{
|
||||
hb_varc_context_t c {font,
|
||||
nullptr,
|
||||
extents,
|
||||
hb_decycler_t {},
|
||||
HB_MAX_GRAPH_EDGE_COUNT,
|
||||
HB_MAX_NESTING_LEVEL,
|
||||
scratch};
|
||||
|
||||
return get_path_at (c, gid,
|
||||
hb_array (font->coords, font->num_coords));
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
|
@ -129,6 +157,89 @@ struct VARC
|
|||
glyphRecords.sanitize (c, this));
|
||||
}
|
||||
|
||||
struct accelerator_t
|
||||
{
|
||||
friend struct VarComponent;
|
||||
|
||||
accelerator_t (hb_face_t *face)
|
||||
{
|
||||
table = hb_sanitize_context_t ().reference_table<VARC> (face);
|
||||
}
|
||||
~accelerator_t ()
|
||||
{
|
||||
auto *scratch = cached_scratch.get_relaxed ();
|
||||
if (scratch)
|
||||
{
|
||||
scratch->~hb_varc_scratch_t ();
|
||||
hb_free (scratch);
|
||||
}
|
||||
|
||||
table.destroy ();
|
||||
}
|
||||
|
||||
bool
|
||||
get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const
|
||||
{
|
||||
if (!table->has_data ()) return false;
|
||||
|
||||
auto *scratch = acquire_scratch ();
|
||||
if (unlikely (!scratch)) return true;
|
||||
bool ret = table->get_path (font, gid, draw_session, *scratch);
|
||||
release_scratch (scratch);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
get_extents (hb_font_t *font,
|
||||
hb_codepoint_t gid,
|
||||
hb_glyph_extents_t *extents) const
|
||||
{
|
||||
if (!table->has_data ()) return false;
|
||||
|
||||
hb_extents_t f_extents;
|
||||
|
||||
auto *scratch = acquire_scratch ();
|
||||
if (unlikely (!scratch)) return true;
|
||||
bool ret = table->get_extents (font, gid, &f_extents, *scratch);
|
||||
release_scratch (scratch);
|
||||
|
||||
if (ret)
|
||||
*extents = f_extents.to_glyph_extents (font->x_scale < 0, font->y_scale < 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
hb_varc_scratch_t *acquire_scratch () const
|
||||
{
|
||||
hb_varc_scratch_t *scratch = cached_scratch.get_acquire ();
|
||||
|
||||
if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr)))
|
||||
{
|
||||
scratch = (hb_varc_scratch_t *) hb_calloc (1, sizeof (hb_varc_scratch_t));
|
||||
if (unlikely (!scratch))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return scratch;
|
||||
}
|
||||
void release_scratch (hb_varc_scratch_t *scratch) const
|
||||
{
|
||||
if (!cached_scratch.cmpexch (nullptr, scratch))
|
||||
{
|
||||
scratch->~hb_varc_scratch_t ();
|
||||
hb_free (scratch);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
hb_blob_ptr_t<VARC> table;
|
||||
hb_atomic_t<hb_varc_scratch_t *> cached_scratch;
|
||||
};
|
||||
|
||||
bool has_data () const { return version.major != 0; }
|
||||
|
||||
protected:
|
||||
FixedVersion<> version; /* Version identifier */
|
||||
Offset32To<Coverage> coverage;
|
||||
|
@ -140,6 +251,10 @@ struct VARC
|
|||
DEFINE_SIZE_STATIC (24);
|
||||
};
|
||||
|
||||
struct VARC_accelerator_t : VARC::accelerator_t {
|
||||
VARC_accelerator_t (hb_face_t *face) : VARC::accelerator_t (face) {}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
//}
|
||||
|
|
|
@ -11,22 +11,48 @@ namespace OT {
|
|||
|
||||
struct coord_setter_t
|
||||
{
|
||||
coord_setter_t (hb_array_t<const int> coords) :
|
||||
coords (coords) {}
|
||||
coord_setter_t (hb_array_t<const int> coords_)
|
||||
{
|
||||
length = coords_.length;
|
||||
if (length <= ARRAY_LENGTH (static_coords))
|
||||
hb_memcpy (static_coords, coords_.arrayZ, length * sizeof (int));
|
||||
else
|
||||
dynamic_coords.extend (coords_);
|
||||
}
|
||||
|
||||
int& operator [] (unsigned idx)
|
||||
{
|
||||
if (unlikely (idx >= HB_VAR_COMPOSITE_MAX_AXES))
|
||||
return Crap(int);
|
||||
if (coords.length < idx + 1)
|
||||
coords.resize (idx + 1);
|
||||
return coords[idx];
|
||||
|
||||
if (length <= ARRAY_LENGTH (static_coords))
|
||||
{
|
||||
if (idx < ARRAY_LENGTH (static_coords))
|
||||
{
|
||||
while (length <= idx)
|
||||
static_coords[length++] = 0;
|
||||
return static_coords[idx];
|
||||
}
|
||||
else
|
||||
dynamic_coords.extend (hb_array (static_coords, length));
|
||||
}
|
||||
|
||||
if (dynamic_coords.length <= idx)
|
||||
{
|
||||
if (unlikely (!dynamic_coords.resize (idx + 1)))
|
||||
return Crap(int);
|
||||
length = idx + 1;
|
||||
}
|
||||
return dynamic_coords.arrayZ[idx];
|
||||
}
|
||||
|
||||
hb_array_t<int> get_coords ()
|
||||
{ return coords.as_array (); }
|
||||
{ return length <= ARRAY_LENGTH (static_coords) ? hb_array (static_coords, length) : dynamic_coords.as_array (); }
|
||||
|
||||
hb_vector_t<int> coords;
|
||||
private:
|
||||
hb_vector_t<int> dynamic_coords;
|
||||
unsigned length;
|
||||
int static_coords[sizeof (void *) * 8];
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ struct CompositeGlyphRecord
|
|||
float matrix[4];
|
||||
contour_point_t trans;
|
||||
get_transformation (matrix, trans);
|
||||
if (unlikely (!points.alloc (points.length + 4))) return false; // For phantom points
|
||||
if (unlikely (!points.alloc (points.length + 1 + 4))) return false; // For phantom points
|
||||
points.push (trans);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -251,7 +251,8 @@ struct Glyph
|
|||
composite_contours_p = nullptr;
|
||||
}
|
||||
|
||||
if (!get_points (font, glyf, all_points, &points_with_deltas, head_maxp_info_p, composite_contours_p, false, false))
|
||||
hb_glyf_scratch_t scratch;
|
||||
if (!get_points (font, glyf, all_points, scratch, &points_with_deltas, head_maxp_info_p, composite_contours_p, false, false))
|
||||
return false;
|
||||
|
||||
// .notdef, set type to empty so we only update metrics and don't compile bytes for
|
||||
|
@ -305,6 +306,7 @@ struct Glyph
|
|||
template <typename accelerator_t>
|
||||
bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
|
||||
contour_point_vector_t &all_points /* OUT */,
|
||||
hb_glyf_scratch_t &scratch,
|
||||
contour_point_vector_t *points_with_deltas = nullptr, /* OUT */
|
||||
head_maxp_info_t * head_maxp_info = nullptr, /* OUT */
|
||||
unsigned *composite_contours = nullptr, /* OUT */
|
||||
|
@ -312,7 +314,6 @@ struct Glyph
|
|||
bool use_my_metrics = true,
|
||||
bool phantom_only = false,
|
||||
hb_array_t<const int> coords = hb_array_t<const int> (),
|
||||
hb_map_t *current_glyphs = nullptr,
|
||||
unsigned int depth = 0,
|
||||
unsigned *edge_count = nullptr) const
|
||||
{
|
||||
|
@ -322,10 +323,6 @@ struct Glyph
|
|||
if (unlikely (*edge_count > HB_MAX_GRAPH_EDGE_COUNT)) return false;
|
||||
(*edge_count)++;
|
||||
|
||||
hb_map_t current_glyphs_stack;
|
||||
if (current_glyphs == nullptr)
|
||||
current_glyphs = ¤t_glyphs_stack;
|
||||
|
||||
if (head_maxp_info)
|
||||
{
|
||||
head_maxp_info->maxComponentDepth = hb_max (head_maxp_info->maxComponentDepth, depth);
|
||||
|
@ -334,8 +331,7 @@ struct Glyph
|
|||
if (!coords)
|
||||
coords = hb_array (font->coords, font->num_coords);
|
||||
|
||||
contour_point_vector_t stack_points;
|
||||
contour_point_vector_t &points = type == SIMPLE ? all_points : stack_points;
|
||||
contour_point_vector_t &points = type == SIMPLE ? all_points : scratch.comp_points;
|
||||
unsigned old_length = points.length;
|
||||
|
||||
switch (type) {
|
||||
|
@ -388,36 +384,53 @@ struct Glyph
|
|||
|
||||
#ifndef HB_NO_VAR
|
||||
if (coords)
|
||||
glyf_accelerator.gvar->apply_deltas_to_points (gid,
|
||||
coords,
|
||||
points.as_array ().sub_array (old_length),
|
||||
phantom_only && type == SIMPLE);
|
||||
{
|
||||
#ifndef HB_NO_BEYOND_64K
|
||||
if (glyf_accelerator.GVAR->has_data ())
|
||||
glyf_accelerator.GVAR->apply_deltas_to_points (gid,
|
||||
coords,
|
||||
points.as_array ().sub_array (old_length),
|
||||
scratch,
|
||||
phantom_only && type == SIMPLE);
|
||||
else
|
||||
#endif
|
||||
glyf_accelerator.gvar->apply_deltas_to_points (gid,
|
||||
coords,
|
||||
points.as_array ().sub_array (old_length),
|
||||
scratch,
|
||||
phantom_only && type == SIMPLE);
|
||||
}
|
||||
#endif
|
||||
|
||||
// mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it
|
||||
// with child glyphs' points
|
||||
if (points_with_deltas != nullptr && depth == 0 && type == COMPOSITE)
|
||||
{
|
||||
if (unlikely (!points_with_deltas->resize (points.length))) return false;
|
||||
assert (old_length == 0);
|
||||
*points_with_deltas = points;
|
||||
}
|
||||
|
||||
float shift = 0;
|
||||
switch (type) {
|
||||
case SIMPLE:
|
||||
if (depth == 0 && head_maxp_info)
|
||||
head_maxp_info->maxPoints = hb_max (head_maxp_info->maxPoints, all_points.length - old_length - 4);
|
||||
shift = phantoms[PHANTOM_LEFT].x;
|
||||
break;
|
||||
case COMPOSITE:
|
||||
{
|
||||
hb_decycler_node_t decycler_node (scratch.decycler);
|
||||
|
||||
unsigned int comp_index = 0;
|
||||
for (auto &item : get_composite_iterator ())
|
||||
{
|
||||
hb_codepoint_t item_gid = item.get_gid ();
|
||||
|
||||
if (unlikely (current_glyphs->has (item_gid)))
|
||||
if (unlikely (!decycler_node.visit (item_gid)))
|
||||
{
|
||||
comp_index++;
|
||||
continue;
|
||||
|
||||
current_glyphs->add (item_gid);
|
||||
}
|
||||
|
||||
unsigned old_count = all_points.length;
|
||||
|
||||
|
@ -426,6 +439,7 @@ struct Glyph
|
|||
.get_points (font,
|
||||
glyf_accelerator,
|
||||
all_points,
|
||||
scratch,
|
||||
points_with_deltas,
|
||||
head_maxp_info,
|
||||
composite_contours,
|
||||
|
@ -433,14 +447,16 @@ struct Glyph
|
|||
use_my_metrics,
|
||||
phantom_only,
|
||||
coords,
|
||||
current_glyphs,
|
||||
depth + 1,
|
||||
edge_count)))
|
||||
{
|
||||
current_glyphs->del (item_gid);
|
||||
points.resize (old_length);
|
||||
return false;
|
||||
}
|
||||
|
||||
// points might have been reallocated. Relocate phantoms.
|
||||
phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
|
||||
|
||||
auto comp_points = all_points.as_array ().sub_array (old_count);
|
||||
|
||||
/* Copy phantom points from component if USE_MY_METRICS flag set */
|
||||
|
@ -455,7 +471,7 @@ struct Glyph
|
|||
item.get_transformation (matrix, default_trans);
|
||||
|
||||
/* Apply component transformation & translation (with deltas applied) */
|
||||
item.transform_points (comp_points, matrix, points[comp_index]);
|
||||
item.transform_points (comp_points, matrix, points[old_length + comp_index]);
|
||||
}
|
||||
|
||||
if (item.is_anchored () && !phantom_only)
|
||||
|
@ -476,12 +492,11 @@ struct Glyph
|
|||
|
||||
if (all_points.length > HB_GLYF_MAX_POINTS)
|
||||
{
|
||||
current_glyphs->del (item_gid);
|
||||
points.resize (old_length);
|
||||
return false;
|
||||
}
|
||||
|
||||
comp_index++;
|
||||
current_glyphs->del (item_gid);
|
||||
}
|
||||
|
||||
if (head_maxp_info && depth == 0)
|
||||
|
@ -492,9 +507,13 @@ struct Glyph
|
|||
head_maxp_info->maxComponentElements = hb_max (head_maxp_info->maxComponentElements, comp_index);
|
||||
}
|
||||
all_points.extend (phantoms);
|
||||
shift = phantoms[PHANTOM_LEFT].x;
|
||||
points.resize (old_length);
|
||||
} break;
|
||||
case EMPTY:
|
||||
all_points.extend (phantoms);
|
||||
shift = phantoms[PHANTOM_LEFT].x;
|
||||
points.resize (old_length);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -503,10 +522,9 @@ struct Glyph
|
|||
/* Undocumented rasterizer behavior:
|
||||
* Shift points horizontally by the updated left side bearing
|
||||
*/
|
||||
float v = -phantoms[PHANTOM_LEFT].x;
|
||||
if (v)
|
||||
if (shift)
|
||||
for (auto &point : all_points)
|
||||
point.x += v;
|
||||
point.x -= shift;
|
||||
}
|
||||
|
||||
return !all_points.in_error ();
|
||||
|
|
|
@ -127,19 +127,20 @@ struct SimpleGlyph
|
|||
hb_array_t<contour_point_t> points_ /* IN/OUT */,
|
||||
const HBUINT8 *end)
|
||||
{
|
||||
auto *points = points_.arrayZ;
|
||||
unsigned count = points_.length;
|
||||
for (unsigned int i = 0; i < count;)
|
||||
{
|
||||
if (unlikely (p + 1 > end)) return false;
|
||||
uint8_t flag = *p++;
|
||||
points_.arrayZ[i++].flag = flag;
|
||||
points[i++].flag = flag;
|
||||
if (flag & FLAG_REPEAT)
|
||||
{
|
||||
if (unlikely (p + 1 > end)) return false;
|
||||
unsigned int repeat_count = *p++;
|
||||
unsigned stop = hb_min (i + repeat_count, count);
|
||||
for (; i < stop; i++)
|
||||
points_.arrayZ[i].flag = flag;
|
||||
points[i].flag = flag;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -160,10 +161,7 @@ struct SimpleGlyph
|
|||
if (flag & short_flag)
|
||||
{
|
||||
if (unlikely (p + 1 > end)) return false;
|
||||
if (flag & same_flag)
|
||||
v += *p++;
|
||||
else
|
||||
v -= *p++;
|
||||
v += (bool(flag & same_flag) * 2 - 1) * *p++;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -190,7 +188,7 @@ struct SimpleGlyph
|
|||
unsigned int num_points = endPtsOfContours[num_contours - 1] + 1;
|
||||
|
||||
unsigned old_length = points.length;
|
||||
points.alloc_exact (points.length + num_points + 4); // Allocate for phantom points, to avoid a possible copy
|
||||
points.alloc (points.length + num_points + 4); // Allocate for phantom points, to avoid a possible copy
|
||||
if (unlikely (!points.resize (points.length + num_points, false))) return false;
|
||||
auto points_ = points.as_array ().sub_array (old_length);
|
||||
if (!phantom_only)
|
||||
|
|
|
@ -172,6 +172,9 @@ struct glyf_accelerator_t
|
|||
glyf_table = nullptr;
|
||||
#ifndef HB_NO_VAR
|
||||
gvar = nullptr;
|
||||
#ifndef HB_NO_BEYOND_64K
|
||||
GVAR = nullptr;
|
||||
#endif
|
||||
#endif
|
||||
hmtx = nullptr;
|
||||
#ifndef HB_NO_VERTICAL
|
||||
|
@ -187,6 +190,9 @@ struct glyf_accelerator_t
|
|||
glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face);
|
||||
#ifndef HB_NO_VAR
|
||||
gvar = face->table.gvar;
|
||||
#ifndef HB_NO_BEYOND_64K
|
||||
GVAR = face->table.GVAR;
|
||||
#endif
|
||||
#endif
|
||||
hmtx = face->table.hmtx;
|
||||
#ifndef HB_NO_VERTICAL
|
||||
|
@ -198,6 +204,13 @@ struct glyf_accelerator_t
|
|||
}
|
||||
~glyf_accelerator_t ()
|
||||
{
|
||||
auto *scratch = cached_scratch.get_relaxed ();
|
||||
if (scratch)
|
||||
{
|
||||
scratch->~hb_glyf_scratch_t ();
|
||||
hb_free (scratch);
|
||||
}
|
||||
|
||||
glyf_table.destroy ();
|
||||
}
|
||||
|
||||
|
@ -206,21 +219,16 @@ struct glyf_accelerator_t
|
|||
protected:
|
||||
template<typename T>
|
||||
bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer,
|
||||
hb_array_t<const int> coords = hb_array_t<const int> ()) const
|
||||
hb_array_t<const int> coords,
|
||||
hb_glyf_scratch_t &scratch) const
|
||||
{
|
||||
if (!coords)
|
||||
coords = hb_array (font->coords, font->num_coords);
|
||||
|
||||
if (gid >= num_glyphs) return false;
|
||||
|
||||
/* Making this allocfree is not that easy
|
||||
https://github.com/harfbuzz/harfbuzz/issues/2095
|
||||
mostly because of gvar handling in VF fonts,
|
||||
perhaps a separate path for non-VF fonts can be considered */
|
||||
contour_point_vector_t all_points;
|
||||
auto &all_points = scratch.all_points;
|
||||
all_points.resize (0);
|
||||
|
||||
bool phantom_only = !consumer.is_consuming_contour_points ();
|
||||
if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, nullptr, nullptr, true, true, phantom_only, coords)))
|
||||
if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, scratch, nullptr, nullptr, nullptr, true, true, phantom_only, coords)))
|
||||
return false;
|
||||
|
||||
unsigned count = all_points.length;
|
||||
|
@ -372,7 +380,12 @@ struct glyf_accelerator_t
|
|||
|
||||
contour_point_t phantoms[glyf_impl::PHANTOM_COUNT];
|
||||
if (font->num_coords)
|
||||
success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms, false));
|
||||
{
|
||||
hb_glyf_scratch_t scratch;
|
||||
success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms, false),
|
||||
hb_array (font->coords, font->num_coords),
|
||||
scratch);
|
||||
}
|
||||
|
||||
if (unlikely (!success))
|
||||
return
|
||||
|
@ -392,9 +405,11 @@ struct glyf_accelerator_t
|
|||
if (unlikely (gid >= num_glyphs)) return false;
|
||||
|
||||
hb_glyph_extents_t extents;
|
||||
|
||||
hb_glyf_scratch_t scratch;
|
||||
contour_point_t phantoms[glyf_impl::PHANTOM_COUNT];
|
||||
if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms, false))))
|
||||
if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms, false),
|
||||
hb_array (font->coords, font->num_coords),
|
||||
scratch)))
|
||||
return false;
|
||||
|
||||
*lsb = is_vertical
|
||||
|
@ -414,13 +429,29 @@ struct glyf_accelerator_t
|
|||
}
|
||||
|
||||
public:
|
||||
bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const
|
||||
|
||||
bool get_extents (hb_font_t *font,
|
||||
hb_codepoint_t gid,
|
||||
hb_glyph_extents_t *extents) const
|
||||
{ return get_extents_at (font, gid, extents, hb_array (font->coords, font->num_coords)); }
|
||||
|
||||
bool get_extents_at (hb_font_t *font,
|
||||
hb_codepoint_t gid,
|
||||
hb_glyph_extents_t *extents,
|
||||
hb_array_t<const int> coords) const
|
||||
{
|
||||
if (unlikely (gid >= num_glyphs)) return false;
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
if (font->num_coords)
|
||||
return get_points (font, gid, points_aggregator_t (font, extents, nullptr, true));
|
||||
if (coords)
|
||||
{
|
||||
hb_glyf_scratch_t scratch;
|
||||
return get_points (font,
|
||||
gid,
|
||||
points_aggregator_t (font, extents, nullptr, true),
|
||||
coords,
|
||||
scratch);
|
||||
}
|
||||
#endif
|
||||
return glyph_for_gid (gid).get_extents_without_var_scaled (font, *this, extents);
|
||||
}
|
||||
|
@ -455,15 +486,52 @@ struct glyf_accelerator_t
|
|||
|
||||
bool
|
||||
get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const
|
||||
{ return get_points (font, gid, glyf_impl::path_builder_t (font, draw_session)); }
|
||||
{
|
||||
if (!has_data ()) return false;
|
||||
|
||||
hb_glyf_scratch_t *scratch;
|
||||
|
||||
// Borrow the cached strach buffer.
|
||||
{
|
||||
scratch = cached_scratch.get_acquire ();
|
||||
if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr)))
|
||||
{
|
||||
scratch = (hb_glyf_scratch_t *) hb_calloc (1, sizeof (hb_glyf_scratch_t));
|
||||
if (unlikely (!scratch))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool ret = get_points (font, gid, glyf_impl::path_builder_t (font, draw_session),
|
||||
hb_array (font->coords, font->num_coords),
|
||||
*scratch);
|
||||
|
||||
// Put it back.
|
||||
if (!cached_scratch.cmpexch (nullptr, scratch))
|
||||
{
|
||||
scratch->~hb_glyf_scratch_t ();
|
||||
hb_free (scratch);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
get_path_at (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session,
|
||||
hb_array_t<const int> coords) const
|
||||
{ return get_points (font, gid, glyf_impl::path_builder_t (font, draw_session), coords); }
|
||||
hb_array_t<const int> coords,
|
||||
hb_glyf_scratch_t &scratch) const
|
||||
{
|
||||
if (!has_data ()) return false;
|
||||
return get_points (font, gid, glyf_impl::path_builder_t (font, draw_session),
|
||||
coords,
|
||||
scratch);
|
||||
}
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
const gvar_accelerator_t *gvar;
|
||||
#ifndef HB_NO_BEYOND_64K
|
||||
const GVAR_accelerator_t *GVAR;
|
||||
#endif
|
||||
#endif
|
||||
const hmtx_accelerator_t *hmtx;
|
||||
#ifndef HB_NO_VERTICAL
|
||||
|
@ -475,6 +543,7 @@ struct glyf_accelerator_t
|
|||
unsigned int num_glyphs;
|
||||
hb_blob_ptr_t<loca> loca_table;
|
||||
hb_blob_ptr_t<glyf> glyf_table;
|
||||
hb_atomic_t<hb_glyf_scratch_t *> cached_scratch;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ struct path_builder_t
|
|||
{
|
||||
bool is_on_curve = point.flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE;
|
||||
#ifdef HB_NO_CUBIC_GLYF
|
||||
bool is_cubic = false;
|
||||
constexpr bool is_cubic = false;
|
||||
#else
|
||||
bool is_cubic = !is_on_curve && (point.flag & glyf_impl::SimpleGlyph::FLAG_CUBIC);
|
||||
#endif
|
||||
|
|
2
src/addTable.py
Normal file → Executable file
2
src/addTable.py
Normal file → Executable file
|
@ -1,3 +1,5 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
from fontTools.ttLib import TTFont
|
||||
from fontTools.ttLib.tables.DefaultTable import DefaultTable
|
||||
|
|
|
@ -22,30 +22,30 @@ if not OBJS:
|
|||
stat = 0
|
||||
tested = 0
|
||||
|
||||
for obj in OBJS:
|
||||
result = subprocess.run(objdump.split () + ['-t', obj], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
result = subprocess.run(objdump.split () + ['-t'] + OBJS, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
||||
if result.returncode:
|
||||
if result.stderr.find (b'not recognized') != -1:
|
||||
# https://github.com/harfbuzz/harfbuzz/issues/3019
|
||||
print ('objdump %s returned "not recognized", skipping' % obj)
|
||||
continue
|
||||
print ('objdump %s returned error:\n%s' % (obj, result.stderr.decode ('utf-8')))
|
||||
stat = 2
|
||||
if result.returncode:
|
||||
if result.stderr.find (b'not recognized') != -1:
|
||||
# https://github.com/harfbuzz/harfbuzz/issues/3019
|
||||
print ('objdump %s returned "not recognized", skipping')
|
||||
else:
|
||||
print ('objdump returned error:\n%s' % (result.stderr.decode ('utf-8')))
|
||||
stat = 2
|
||||
else:
|
||||
tested = 1
|
||||
|
||||
result = result.stdout.decode ('utf-8')
|
||||
result = result.stdout.decode ('utf-8')
|
||||
|
||||
# Checking that no object file has static initializers
|
||||
for l in re.findall (r'^.*\.[cd]tors.*$', result, re.MULTILINE):
|
||||
if not re.match (r'.*\b0+\b', l):
|
||||
print ('Ouch, %s has static initializers/finalizers' % obj)
|
||||
stat = 1
|
||||
# Checking that no object file has static initializers
|
||||
for l in re.findall (r'^.*\.[cd]tors.*$', result, re.MULTILINE):
|
||||
if not re.match (r'.*\b0+\b', l):
|
||||
print ('Ouch, library has static initializers/finalizers')
|
||||
stat = 1
|
||||
|
||||
# Checking that no object file has lazy static C++ constructors/destructors or other such stuff
|
||||
if ('__cxa_' in result) and ('__ubsan_handle' not in result):
|
||||
print ('Ouch, %s has lazy static C++ constructors/destructors or other such stuff' % obj)
|
||||
stat = 1
|
||||
# Checking that no object file has lazy static C++ constructors/destructors or other such stuff
|
||||
if ('__cxa_' in result) and ('__ubsan_handle' not in result):
|
||||
print ('Ouch, library has lazy static C++ constructors/destructors or other such stuff')
|
||||
stat = 1
|
||||
|
||||
tested += 1
|
||||
|
||||
sys.exit (stat if tested else 77)
|
||||
|
|
|
@ -7,18 +7,26 @@ os.environ['LC_ALL'] = 'C' # otherwise 'nm' prints in wrong order
|
|||
builddir = os.getenv ('builddir', os.path.dirname (__file__))
|
||||
libs = os.getenv ('libs', '.libs')
|
||||
|
||||
IGNORED_SYMBOLS = '|'.join(['_fini', '_init', '_fdata', '_ftext', '_fbss',
|
||||
IGNORED_SYMBOLS = ['_fini', '_init', '_fdata', '_ftext', '_fbss',
|
||||
'__bss_start', '__bss_start__', '__bss_end__', '_edata', '_end', '_bss_end__',
|
||||
'__end__', '__gcov_.*', 'llvm_.*', 'flush_fn_list', 'writeout_fn_list', 'mangle_path',
|
||||
'lprofDirMode', 'reset_fn_list'])
|
||||
'lprofDirMode', 'reset_fn_list']
|
||||
|
||||
# Rust
|
||||
IGNORED_SYMBOLS += [
|
||||
'rust_eh_personality',
|
||||
'_ZN3std9panicking11EMPTY_PANIC.*', # 'std::panicking::EMPTY_PANIC::.*'
|
||||
'_ZN3std3sys3pal4unix4args3imp15ARGV_INIT_ARRAY.*', # 'std::sys::pal::unix::args::imp::ARGV_INIT_ARRAY::.*'
|
||||
'_ZN17compiler_builtins4math4libm7generic4sqrt9RSQRT_TAB.*', # 'compiler_builtins::math::libm::generic::sqrt::RSQRT_TAB::.*'
|
||||
]
|
||||
|
||||
IGNORED_SYMBOLS = '|'.join (IGNORED_SYMBOLS)
|
||||
|
||||
nm = os.getenv ('NM', shutil.which ('nm'))
|
||||
if not nm:
|
||||
print ('check-symbols.py: \'nm\' not found; skipping test')
|
||||
sys.exit (77)
|
||||
|
||||
cxxfilt = shutil.which ('c++filt')
|
||||
|
||||
tested = False
|
||||
stat = 0
|
||||
|
||||
|
@ -34,12 +42,6 @@ for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-icu', 'harfbuzz-gobject'
|
|||
for s in re.findall (r'^.+ [BCDGIRSTu] .+$', subprocess.check_output (nm.split() + [so]).decode ('utf-8'), re.MULTILINE)
|
||||
if not re.match (r'.* %s(%s)\b' % (symprefix, IGNORED_SYMBOLS), s)]
|
||||
|
||||
# run again c++filt also if is available
|
||||
if cxxfilt:
|
||||
EXPORTED_SYMBOLS = subprocess.check_output (
|
||||
[cxxfilt], input='\n'.join (EXPORTED_SYMBOLS).encode ()
|
||||
).decode ('utf-8').splitlines ()
|
||||
|
||||
prefix = (symprefix + os.path.basename (so)).replace ('libharfbuzz', 'hb').replace ('-', '_').split ('.')[0]
|
||||
|
||||
print ('Checking that %s does not expose internal symbols' % so)
|
||||
|
|
95
src/fontations/Cargo.lock
generated
Normal file
95
src/fontations/Cargo.lock
generated
Normal file
|
@ -0,0 +1,95 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540"
|
||||
dependencies = [
|
||||
"bytemuck_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck_derive"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "font-types"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d868ec188a98bb014c606072edd47e52e7ab7297db943b0b28503121e1d037bd"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "harfbuzz_fontations"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"read-fonts",
|
||||
"skrifa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.94"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "read-fonts"
|
||||
version = "0.27.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f14974c88fb4fd0a7203719f98020209248c9dbebaf9d10d860337797a905097"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"font-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "skrifa"
|
||||
version = "0.29.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c0ca53de9bb9bee1720c727606275148463cd938eb6bde249dcedeec4967747"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"read-fonts",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
28
src/fontations/Cargo.toml
Normal file
28
src/fontations/Cargo.toml
Normal file
|
@ -0,0 +1,28 @@
|
|||
[package]
|
||||
name = "harfbuzz_fontations"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
read-fonts = "0.27"
|
||||
skrifa = "0.29.2"
|
||||
|
||||
[lib]
|
||||
name = "harfbuzz_fontations"
|
||||
path = "lib.rs"
|
||||
crate-type = ["staticlib"]
|
||||
|
||||
[profile.release]
|
||||
strip = true
|
||||
lto = "fat"
|
||||
panic = "abort"
|
||||
overflow-checks = false
|
||||
codegen-units = 1
|
||||
|
||||
[profile.debugoptimized]
|
||||
inherits = "release"
|
||||
debug = true
|
||||
codegen-units = 16
|
||||
strip = false
|
||||
|
||||
[profile.dev]
|
||||
lto = "fat"
|
1132
src/fontations/lib.rs
Normal file
1132
src/fontations/lib.rs
Normal file
File diff suppressed because it is too large
Load diff
105
src/fontations/meson.build
Normal file
105
src/fontations/meson.build
Normal file
|
@ -0,0 +1,105 @@
|
|||
rust = import('unstable-rust')
|
||||
|
||||
hb_rs = rust.bindgen(
|
||||
input : '../hb.h',
|
||||
output : 'hb.rs',
|
||||
include_directories: incsrc,
|
||||
args : ['--allowlist-function=hb_.*',
|
||||
'--allowlist-type=hb_.*',
|
||||
'--no-copy=hb_.*',
|
||||
],
|
||||
)
|
||||
|
||||
cargo = find_program('cargo')
|
||||
rustfmt = find_program('rustfmt')
|
||||
|
||||
rust_flags = ''
|
||||
cargo_args = [
|
||||
'--package', 'harfbuzz_fontations',
|
||||
'--lib',
|
||||
'--target-dir', meson.current_build_dir(),
|
||||
'--manifest-path', meson.current_source_dir() / 'Cargo.toml',
|
||||
'-Z', 'build-std=std,panic_abort',
|
||||
'-Z', 'build-std-features=panic_immediate_abort',
|
||||
]
|
||||
|
||||
buildtype = get_option('buildtype')
|
||||
if buildtype == 'release' or buildtype == 'debugoptimized'
|
||||
cargo_args += ['--profile', buildtype]
|
||||
endif
|
||||
|
||||
opt_level = get_option('optimization')
|
||||
rust_flags += ' -C opt-level=' + opt_level
|
||||
|
||||
harfbuzz_fontations = custom_target(
|
||||
'harfbuzz_fontations',
|
||||
input: ['lib.rs', 'Cargo.toml', 'Cargo.lock'],
|
||||
output: ['libharfbuzz_fontations.a'],
|
||||
depends: [hb_rs],
|
||||
env: ['OUT_DIR=' + meson.current_build_dir(),
|
||||
'RUSTFLAGS=' + rust_flags,
|
||||
],
|
||||
command: [
|
||||
cargo, 'build',
|
||||
] + cargo_args + [
|
||||
'-Z', 'unstable-options',
|
||||
'--artifact-dir', meson.current_build_dir(),
|
||||
],
|
||||
install: true,
|
||||
install_dir: join_paths(get_option('prefix'), 'lib'),
|
||||
)
|
||||
|
||||
harfbuzz_fontations_dep = declare_dependency(
|
||||
link_with: harfbuzz_fontations,
|
||||
)
|
||||
|
||||
clippy_fix = run_target(
|
||||
'clippy-fix',
|
||||
env: ['OUT_DIR=' + meson.current_build_dir()],
|
||||
depends: [hb_rs, harfbuzz_fontations],
|
||||
command: [
|
||||
cargo, 'clippy',
|
||||
] + cargo_args + [
|
||||
'--allow-dirty', '--fix',
|
||||
],
|
||||
)
|
||||
if get_option('tests').enabled() and cargo.found()
|
||||
test(
|
||||
'clippy',
|
||||
cargo,
|
||||
env: ['OUT_DIR=' + meson.current_build_dir()],
|
||||
depends: [hb_rs, harfbuzz_fontations],
|
||||
args: [
|
||||
'clippy',
|
||||
] + cargo_args + [
|
||||
'--', '-D', 'warnings',
|
||||
],
|
||||
timeout: 120,
|
||||
)
|
||||
endif
|
||||
|
||||
rustfmt_fix = run_target(
|
||||
'rustfmt-fix',
|
||||
env: ['OUT_DIR=' + meson.current_build_dir()],
|
||||
depends: [hb_rs],
|
||||
command: [
|
||||
rustfmt,
|
||||
'--edition', '2021',
|
||||
'--',
|
||||
meson.current_source_dir() / 'lib.rs',
|
||||
],
|
||||
)
|
||||
if get_option('tests').enabled() and rustfmt.found()
|
||||
test(
|
||||
'rustfmt',
|
||||
rustfmt,
|
||||
env: ['OUT_DIR=' + meson.current_build_dir()],
|
||||
depends: [hb_rs],
|
||||
args: [
|
||||
'--check',
|
||||
'--edition', '2021',
|
||||
'--',
|
||||
meson.current_source_dir() / 'lib.rs',
|
||||
],
|
||||
)
|
||||
endif
|
|
@ -21,6 +21,10 @@ if '--experimental-api' not in sys.argv:
|
|||
experimental_symbols = \
|
||||
"""hb_shape_justify
|
||||
hb_subset_input_override_name_table
|
||||
hb_subset_cff_get_charstring_data
|
||||
hb_subset_cff_get_charstrings_index
|
||||
hb_subset_cff2_get_charstring_data
|
||||
hb_subset_cff2_get_charstrings_index
|
||||
""".splitlines ()
|
||||
symbols = [x for x in symbols if x not in experimental_symbols]
|
||||
symbols = "\n".join (symbols)
|
||||
|
|
|
@ -19,7 +19,9 @@ outdir = os.path.dirname (OUTPUT)
|
|||
shutil.copy (INPUT, outdir)
|
||||
rl = os.path.basename (INPUT)
|
||||
hh = rl.replace ('.rl', '.hh')
|
||||
subprocess.Popen (ragel.split() + ['-e', '-F1', '-o', hh, rl], cwd=outdir).wait ()
|
||||
ret = subprocess.Popen (ragel.split() + ['-e', '-F1', '-o', hh, rl], cwd=outdir).wait ()
|
||||
if ret:
|
||||
sys.exit (ret)
|
||||
|
||||
# copy it also to src/
|
||||
shutil.copyfile (os.path.join (outdir, hh), os.path.join (CURRENT_SOURCE_DIR, hh))
|
||||
|
|
|
@ -57,6 +57,8 @@
|
|||
#include "hb-subset-input.cc"
|
||||
#include "hb-subset-instancer-iup.cc"
|
||||
#include "hb-subset-instancer-solver.cc"
|
||||
#include "hb-subset-plan-layout.cc"
|
||||
#include "hb-subset-plan-var.cc"
|
||||
#include "hb-subset-plan.cc"
|
||||
#include "hb-subset-serialize.cc"
|
||||
#include "hb-subset.cc"
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
#include "hb-common.cc"
|
||||
#include "hb-coretext-font.cc"
|
||||
#include "hb-coretext-shape.cc"
|
||||
#include "hb-coretext.cc"
|
||||
#include "hb-directwrite-font.cc"
|
||||
#include "hb-directwrite-shape.cc"
|
||||
#include "hb-directwrite.cc"
|
||||
#include "hb-draw.cc"
|
||||
#include "hb-face-builder.cc"
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
|
||||
#include "hb-aat-layout.hh"
|
||||
#include "hb-aat-map.hh"
|
||||
#include "hb-ot-layout-common.hh"
|
||||
#include "hb-ot-layout-gdef-table.hh"
|
||||
#include "hb-open-type.hh"
|
||||
#include "hb-cache.hh"
|
||||
#include "hb-bit-set.hh"
|
||||
|
@ -48,6 +50,61 @@ struct ankr;
|
|||
using hb_aat_class_cache_t = hb_cache_t<15, 8, 7>;
|
||||
static_assert (sizeof (hb_aat_class_cache_t) == 256, "");
|
||||
|
||||
struct hb_aat_scratch_t
|
||||
{
|
||||
hb_aat_scratch_t () = default;
|
||||
hb_aat_scratch_t (const hb_aat_scratch_t &) = delete;
|
||||
|
||||
hb_aat_scratch_t (hb_aat_scratch_t &&o)
|
||||
{
|
||||
buffer_glyph_set.set_relaxed (o.buffer_glyph_set.get_relaxed ());
|
||||
o.buffer_glyph_set.set_relaxed (nullptr);
|
||||
}
|
||||
hb_aat_scratch_t & operator = (hb_aat_scratch_t &&o)
|
||||
{
|
||||
buffer_glyph_set.set_relaxed (o.buffer_glyph_set.get_relaxed ());
|
||||
o.buffer_glyph_set.set_relaxed (nullptr);
|
||||
return *this;
|
||||
}
|
||||
~hb_aat_scratch_t ()
|
||||
{
|
||||
auto *s = buffer_glyph_set.get_relaxed ();
|
||||
if (unlikely (!s))
|
||||
return;
|
||||
s->fini ();
|
||||
hb_free (s);
|
||||
}
|
||||
|
||||
hb_bit_set_t *create_buffer_glyph_set () const
|
||||
{
|
||||
hb_bit_set_t *s = buffer_glyph_set.get_acquire ();
|
||||
if (s && buffer_glyph_set.cmpexch (s, nullptr))
|
||||
return s;
|
||||
|
||||
s = (hb_bit_set_t *) hb_calloc (1, sizeof (hb_bit_set_t));
|
||||
if (unlikely (!s))
|
||||
return nullptr;
|
||||
s->init ();
|
||||
|
||||
return s;
|
||||
}
|
||||
void destroy_buffer_glyph_set (hb_bit_set_t *s) const
|
||||
{
|
||||
if (unlikely (!s))
|
||||
return;
|
||||
if (buffer_glyph_set.cmpexch (nullptr, s))
|
||||
return;
|
||||
s->fini ();
|
||||
hb_free (s);
|
||||
}
|
||||
|
||||
mutable hb_atomic_t<hb_bit_set_t *> buffer_glyph_set;
|
||||
};
|
||||
|
||||
enum { DELETED_GLYPH = 0xFFFF };
|
||||
|
||||
#define HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED HB_BUFFER_SCRATCH_FLAG_SHAPER0
|
||||
|
||||
struct hb_aat_apply_context_t :
|
||||
hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
|
||||
{
|
||||
|
@ -64,10 +121,11 @@ struct hb_aat_apply_context_t :
|
|||
hb_buffer_t *buffer;
|
||||
hb_sanitize_context_t sanitizer;
|
||||
const ankr *ankr_table;
|
||||
const OT::GDEF *gdef_table;
|
||||
const OT::GDEF &gdef;
|
||||
bool has_glyph_classes;
|
||||
const hb_sorted_vector_t<hb_aat_map_t::range_flags_t> *range_flags = nullptr;
|
||||
bool using_buffer_glyph_set = false;
|
||||
hb_bit_set_t buffer_glyph_set;
|
||||
hb_bit_set_t *buffer_glyph_set = nullptr;
|
||||
const hb_bit_set_t *left_set = nullptr;
|
||||
const hb_bit_set_t *right_set = nullptr;
|
||||
const hb_bit_set_t *machine_glyph_set = nullptr;
|
||||
|
@ -90,15 +148,15 @@ struct hb_aat_apply_context_t :
|
|||
|
||||
void setup_buffer_glyph_set ()
|
||||
{
|
||||
using_buffer_glyph_set = buffer->len >= 4;
|
||||
using_buffer_glyph_set = buffer->len >= 4 && buffer_glyph_set;
|
||||
|
||||
if (using_buffer_glyph_set)
|
||||
buffer->collect_codepoints (buffer_glyph_set);
|
||||
if (likely (using_buffer_glyph_set))
|
||||
buffer->collect_codepoints (*buffer_glyph_set);
|
||||
}
|
||||
bool buffer_intersects_machine () const
|
||||
{
|
||||
if (using_buffer_glyph_set)
|
||||
return buffer_glyph_set.intersects (*machine_glyph_set);
|
||||
if (likely (using_buffer_glyph_set))
|
||||
return buffer_glyph_set->intersects (*machine_glyph_set);
|
||||
|
||||
// Faster for shorter buffers.
|
||||
for (unsigned i = 0; i < buffer->len; i++)
|
||||
|
@ -106,6 +164,69 @@ struct hb_aat_apply_context_t :
|
|||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
HB_NODISCARD bool output_glyphs (unsigned int count,
|
||||
const T *glyphs)
|
||||
{
|
||||
if (likely (using_buffer_glyph_set))
|
||||
buffer_glyph_set->add_array (glyphs, count);
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
if (glyphs[i] == DELETED_GLYPH)
|
||||
{
|
||||
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED;
|
||||
_hb_glyph_info_set_aat_deleted (&buffer->cur());
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef HB_NO_OT_LAYOUT
|
||||
if (has_glyph_classes)
|
||||
_hb_glyph_info_set_glyph_props (&buffer->cur(),
|
||||
gdef.get_glyph_props (glyphs[i]));
|
||||
#endif
|
||||
}
|
||||
if (unlikely (!buffer->output_glyph (glyphs[i]))) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
HB_NODISCARD bool replace_glyph (hb_codepoint_t glyph)
|
||||
{
|
||||
if (glyph == DELETED_GLYPH)
|
||||
{
|
||||
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED;
|
||||
_hb_glyph_info_set_aat_deleted (&buffer->cur());
|
||||
}
|
||||
|
||||
if (likely (using_buffer_glyph_set))
|
||||
buffer_glyph_set->add (glyph);
|
||||
#ifndef HB_NO_OT_LAYOUT
|
||||
if (has_glyph_classes)
|
||||
_hb_glyph_info_set_glyph_props (&buffer->cur(),
|
||||
gdef.get_glyph_props (glyph));
|
||||
#endif
|
||||
return buffer->replace_glyph (glyph);
|
||||
}
|
||||
|
||||
HB_NODISCARD bool delete_glyph ()
|
||||
{
|
||||
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED;
|
||||
_hb_glyph_info_set_aat_deleted (&buffer->cur());
|
||||
return buffer->replace_glyph (DELETED_GLYPH);
|
||||
}
|
||||
|
||||
void replace_glyph_inplace (unsigned i, hb_codepoint_t glyph)
|
||||
{
|
||||
buffer->info[i].codepoint = glyph;
|
||||
if (likely (using_buffer_glyph_set))
|
||||
buffer_glyph_set->add (glyph);
|
||||
#ifndef HB_NO_OT_LAYOUT
|
||||
if (has_glyph_classes)
|
||||
_hb_glyph_info_set_glyph_props (&buffer->info[i],
|
||||
gdef.get_glyph_props (glyph));
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -113,8 +234,6 @@ struct hb_aat_apply_context_t :
|
|||
* Lookup Table
|
||||
*/
|
||||
|
||||
enum { DELETED_GLYPH = 0xFFFF };
|
||||
|
||||
template <typename T> struct Lookup;
|
||||
|
||||
template <typename T>
|
||||
|
@ -179,6 +298,7 @@ struct LookupSegmentSingle
|
|||
template <typename set_t, typename filter_t>
|
||||
void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const
|
||||
{
|
||||
if (first == DELETED_GLYPH) return;
|
||||
if (!filter (value)) return;
|
||||
glyphs.add_range (first, last);
|
||||
}
|
||||
|
@ -268,6 +388,7 @@ struct LookupSegmentArray
|
|||
template <typename set_t, typename filter_t>
|
||||
void collect_glyphs_filtered (set_t &glyphs, const void *base, const filter_t &filter) const
|
||||
{
|
||||
if (first == DELETED_GLYPH) return;
|
||||
const auto &values = base+valuesZ;
|
||||
for (hb_codepoint_t i = first; i <= last; i++)
|
||||
if (filter (values[i - first]))
|
||||
|
@ -368,6 +489,7 @@ struct LookupSingle
|
|||
template <typename set_t, typename filter_t>
|
||||
void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const
|
||||
{
|
||||
if (glyph == DELETED_GLYPH) return;
|
||||
if (!filter (value)) return;
|
||||
glyphs.add (glyph);
|
||||
}
|
||||
|
@ -746,6 +868,10 @@ struct StateTable
|
|||
}
|
||||
|
||||
// And glyphs in those classes.
|
||||
|
||||
if (filter (CLASS_DELETED_GLYPH))
|
||||
glyphs.add (DELETED_GLYPH);
|
||||
|
||||
(this+classTable).collect_glyphs_filtered (glyphs, num_glyphs, filter);
|
||||
}
|
||||
|
||||
|
|
|
@ -185,6 +185,9 @@ struct Format1Entry<true>
|
|||
DEFINE_SIZE_STATIC (2);
|
||||
};
|
||||
|
||||
static bool initiateAction (const Entry<EntryData> &entry)
|
||||
{ return entry.flags & Push; }
|
||||
|
||||
static bool performAction (const Entry<EntryData> &entry)
|
||||
{ return entry.data.kernActionIndex != 0xFFFF; }
|
||||
|
||||
|
@ -325,8 +328,9 @@ struct KerxSubTableFormat1
|
|||
}
|
||||
else if (buffer->info[idx].mask & kern_mask)
|
||||
{
|
||||
o.x_advance += c->font->em_scale_x (v);
|
||||
o.x_offset += c->font->em_scale_x (v);
|
||||
auto scaled = c->font->em_scale_x (v);
|
||||
o.x_advance += scaled;
|
||||
o.x_offset += scaled;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -394,10 +398,8 @@ struct KerxSubTableFormat1
|
|||
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);
|
||||
machine.collect_initial_glyphs (left_set, num_glyphs, *this);
|
||||
//machine.collect_glyphs (right_set, num_glyphs); // right_set is unused for machine kerning
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -671,10 +673,8 @@ struct KerxSubTableFormat4
|
|||
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);
|
||||
machine.collect_initial_glyphs (left_set, num_glyphs, *this);
|
||||
//machine.collect_glyphs (right_set, num_glyphs); // right_set is unused for machine kerning
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -921,7 +921,18 @@ struct KerxSubTable
|
|||
* The 'kerx' Table
|
||||
*/
|
||||
|
||||
using kern_accelerator_data_t = hb_vector_t<hb_pair_t<hb_bit_set_t, hb_bit_set_t>>;
|
||||
struct kern_subtable_accelerator_data_t
|
||||
{
|
||||
hb_bit_set_t left_set;
|
||||
hb_bit_set_t right_set;
|
||||
mutable hb_aat_class_cache_t class_cache;
|
||||
};
|
||||
|
||||
struct kern_accelerator_data_t
|
||||
{
|
||||
hb_vector_t<kern_subtable_accelerator_data_t> subtable_accels;
|
||||
hb_aat_scratch_t scratch;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct KerxTable
|
||||
|
@ -985,6 +996,8 @@ struct KerxTable
|
|||
{
|
||||
c->buffer->unsafe_to_concat ();
|
||||
|
||||
c->setup_buffer_glyph_set ();
|
||||
|
||||
typedef typename T::SubTable SubTable;
|
||||
|
||||
bool ret = false;
|
||||
|
@ -996,12 +1009,25 @@ struct KerxTable
|
|||
{
|
||||
bool reverse;
|
||||
|
||||
auto &subtable_accel = accel_data.subtable_accels[i];
|
||||
|
||||
if (!T::Types::extended && (st->u.header.coverage & st->u.header.Variation))
|
||||
goto skip;
|
||||
|
||||
if (HB_DIRECTION_IS_HORIZONTAL (c->buffer->props.direction) != st->u.header.is_horizontal ())
|
||||
goto skip;
|
||||
|
||||
c->left_set = &subtable_accel.left_set;
|
||||
c->right_set = &subtable_accel.right_set;
|
||||
c->machine_glyph_set = &subtable_accel.left_set;
|
||||
c->machine_class_cache = &subtable_accel.class_cache;
|
||||
|
||||
if (!c->buffer_intersects_machine ())
|
||||
{
|
||||
(void) c->buffer->message (c->font, "skipped subtable %u because no glyph matches", c->lookup_index);
|
||||
goto skip;
|
||||
}
|
||||
|
||||
reverse = bool (st->u.header.coverage & st->u.header.Backwards) !=
|
||||
HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
|
||||
|
||||
|
@ -1028,9 +1054,6 @@ struct KerxTable
|
|||
if (reverse)
|
||||
c->buffer->reverse ();
|
||||
|
||||
c->left_set = &accel_data[i].first;
|
||||
c->right_set = &accel_data[i].second;
|
||||
|
||||
{
|
||||
/* See comment in sanitize() for conditional here. */
|
||||
hb_sanitize_with_object_t with (&c->sanitizer, i < count - 1 ? st : (const SubTable *) nullptr);
|
||||
|
@ -1106,9 +1129,13 @@ struct KerxTable
|
|||
unsigned int count = thiz()->tableCount;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
hb_bit_set_t left_set, right_set;
|
||||
st->collect_glyphs (left_set, right_set, num_glyphs);
|
||||
accel_data.push (hb_pair (left_set, right_set));
|
||||
auto &subtable_accel = *accel_data.subtable_accels.push ();
|
||||
if (unlikely (accel_data.subtable_accels.in_error ()))
|
||||
return accel_data;
|
||||
|
||||
st->collect_glyphs (subtable_accel.left_set, subtable_accel.right_set, num_glyphs);
|
||||
subtable_accel.class_cache.clear ();
|
||||
|
||||
st = &StructAfter<SubTable> (*st);
|
||||
}
|
||||
|
||||
|
@ -1137,6 +1164,7 @@ struct KerxTable
|
|||
|
||||
hb_blob_ptr_t<T> table;
|
||||
kern_accelerator_data_t accel_data;
|
||||
hb_aat_scratch_t scratch;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -30,8 +30,6 @@
|
|||
#include "hb-open-type.hh"
|
||||
#include "hb-aat-layout-common.hh"
|
||||
#include "hb-ot-layout.hh"
|
||||
#include "hb-ot-layout-common.hh"
|
||||
#include "hb-ot-layout-gdef-table.hh"
|
||||
#include "hb-aat-map.hh"
|
||||
|
||||
/*
|
||||
|
@ -178,12 +176,6 @@ struct RearrangementSubtable
|
|||
|
||||
StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
|
||||
|
||||
if (!c->buffer_intersects_machine ())
|
||||
{
|
||||
(void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches");
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
driver.drive (&dc, c);
|
||||
|
||||
return_trace (dc.ret);
|
||||
|
@ -242,9 +234,7 @@ struct ContextualSubtable
|
|||
ret (false),
|
||||
c (c_),
|
||||
table (table_),
|
||||
gdef (*c->gdef_table),
|
||||
mark_set (false),
|
||||
has_glyph_classes (gdef.has_glyph_classes ()),
|
||||
mark (0),
|
||||
subs (table+table->substitutionTables) {}
|
||||
|
||||
|
@ -281,12 +271,7 @@ struct ContextualSubtable
|
|||
if (replacement)
|
||||
{
|
||||
buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len));
|
||||
hb_codepoint_t glyph = *replacement;
|
||||
buffer->info[mark].codepoint = glyph;
|
||||
c->buffer_glyph_set.add (glyph);
|
||||
if (has_glyph_classes)
|
||||
_hb_glyph_info_set_glyph_props (&buffer->info[mark],
|
||||
gdef.get_glyph_props (*replacement));
|
||||
c->replace_glyph_inplace (mark, *replacement);
|
||||
ret = true;
|
||||
}
|
||||
|
||||
|
@ -312,12 +297,7 @@ struct ContextualSubtable
|
|||
}
|
||||
if (replacement)
|
||||
{
|
||||
hb_codepoint_t glyph = *replacement;
|
||||
buffer->info[idx].codepoint = glyph;
|
||||
c->buffer_glyph_set.add (glyph);
|
||||
if (has_glyph_classes)
|
||||
_hb_glyph_info_set_glyph_props (&buffer->info[idx],
|
||||
gdef.get_glyph_props (*replacement));
|
||||
c->replace_glyph_inplace (idx, *replacement);
|
||||
ret = true;
|
||||
}
|
||||
|
||||
|
@ -333,9 +313,7 @@ struct ContextualSubtable
|
|||
hb_aat_apply_context_t *c;
|
||||
const ContextualSubtable *table;
|
||||
private:
|
||||
const OT::GDEF &gdef;
|
||||
bool mark_set;
|
||||
bool has_glyph_classes;
|
||||
unsigned int mark;
|
||||
const UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, void, false> &subs;
|
||||
};
|
||||
|
@ -348,12 +326,6 @@ struct ContextualSubtable
|
|||
|
||||
StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
|
||||
|
||||
if (!c->buffer_intersects_machine ())
|
||||
{
|
||||
(void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches");
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
driver.drive (&dc, c);
|
||||
|
||||
return_trace (dc.ret);
|
||||
|
@ -581,7 +553,7 @@ struct LigatureSubtable
|
|||
hb_codepoint_t lig = ligatureData;
|
||||
|
||||
DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig);
|
||||
if (unlikely (!buffer->replace_glyph (lig))) return;
|
||||
if (unlikely (!c->replace_glyph (lig))) return;
|
||||
|
||||
unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u;
|
||||
/* Now go and delete all subsequent components. */
|
||||
|
@ -589,8 +561,7 @@ struct LigatureSubtable
|
|||
{
|
||||
DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
|
||||
if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return;
|
||||
_hb_glyph_info_set_default_ignorable (&buffer->cur());
|
||||
if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return;
|
||||
if (!c->delete_glyph ()) return;
|
||||
}
|
||||
|
||||
if (unlikely (!buffer->move_to (lig_end))) return;
|
||||
|
@ -624,12 +595,6 @@ struct LigatureSubtable
|
|||
|
||||
StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
|
||||
|
||||
if (!c->buffer_intersects_machine ())
|
||||
{
|
||||
(void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches");
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
driver.drive (&dc, c);
|
||||
|
||||
return_trace (dc.ret);
|
||||
|
@ -665,15 +630,6 @@ struct NoncontextualSubtable
|
|||
{
|
||||
TRACE_APPLY (this);
|
||||
|
||||
if (!c->buffer_intersects_machine ())
|
||||
{
|
||||
(void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches");
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
const OT::GDEF &gdef (*c->gdef_table);
|
||||
bool has_glyph_classes = gdef.has_glyph_classes ();
|
||||
|
||||
bool ret = false;
|
||||
unsigned int num_glyphs = c->face->get_num_glyphs ();
|
||||
|
||||
|
@ -703,12 +659,7 @@ struct NoncontextualSubtable
|
|||
const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
|
||||
if (replacement)
|
||||
{
|
||||
hb_codepoint_t glyph = *replacement;
|
||||
info[i].codepoint = glyph;
|
||||
c->buffer_glyph_set.add (glyph);
|
||||
if (has_glyph_classes)
|
||||
_hb_glyph_info_set_glyph_props (&info[i],
|
||||
gdef.get_glyph_props (*replacement));
|
||||
c->replace_glyph_inplace (i, *replacement);
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
@ -850,9 +801,7 @@ struct InsertionSubtable
|
|||
if (buffer->idx < buffer->len && !before)
|
||||
if (unlikely (!buffer->copy_glyph ())) return;
|
||||
/* TODO We ignore KashidaLike setting. */
|
||||
if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
c->buffer_glyph_set.add (glyphs[i]);
|
||||
if (unlikely (!c->output_glyphs (count, glyphs))) return;
|
||||
ret = true;
|
||||
if (buffer->idx < buffer->len && !before)
|
||||
buffer->skip_glyph ();
|
||||
|
@ -881,7 +830,8 @@ struct InsertionSubtable
|
|||
if (buffer->idx < buffer->len && !before)
|
||||
if (unlikely (!buffer->copy_glyph ())) return;
|
||||
/* TODO We ignore KashidaLike setting. */
|
||||
if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
|
||||
if (unlikely (!c->output_glyphs (count, glyphs))) return;
|
||||
ret = true;
|
||||
if (buffer->idx < buffer->len && !before)
|
||||
buffer->skip_glyph ();
|
||||
|
||||
|
@ -921,12 +871,6 @@ struct InsertionSubtable
|
|||
|
||||
StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
|
||||
|
||||
if (!c->buffer_intersects_machine ())
|
||||
{
|
||||
(void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches");
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
driver.drive (&dc, c);
|
||||
|
||||
return_trace (dc.ret);
|
||||
|
@ -1224,6 +1168,7 @@ struct Chain
|
|||
if (hb_none (hb_iter (c->range_flags) |
|
||||
hb_map ([subtable_flags] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable_flags & (_.flags); })))
|
||||
goto skip;
|
||||
|
||||
c->subtable_flags = subtable_flags;
|
||||
c->machine_glyph_set = accel ? &accel->subtables[i].glyph_set : &Null(hb_bit_set_t);
|
||||
c->machine_class_cache = accel ? &accel->subtables[i].class_cache : nullptr;
|
||||
|
@ -1233,6 +1178,12 @@ struct Chain
|
|||
bool (coverage & ChainSubtable<Types>::Vertical))
|
||||
goto skip;
|
||||
|
||||
if (!c->buffer_intersects_machine ())
|
||||
{
|
||||
(void) c->buffer->message (c->font, "skipped chainsubtable %u because no glyph matches", c->lookup_index);
|
||||
goto skip;
|
||||
}
|
||||
|
||||
/* Buffer contents is always in logical direction. Determine if
|
||||
* we need to reverse before applying this subtable. We reverse
|
||||
* back after if we did reverse indeed.
|
||||
|
@ -1376,7 +1327,7 @@ struct mortmorx
|
|||
|
||||
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));
|
||||
this->accels = (hb_atomic_t<hb_aat_layout_chain_accelerator_t *> *) hb_calloc (this->chain_count, sizeof (*accels));
|
||||
if (unlikely (!this->accels))
|
||||
{
|
||||
this->chain_count = 0;
|
||||
|
@ -1423,7 +1374,8 @@ struct mortmorx
|
|||
|
||||
hb_blob_ptr_t<T> table;
|
||||
unsigned int chain_count;
|
||||
hb_atomic_ptr_t<hb_aat_layout_chain_accelerator_t> *accels;
|
||||
hb_atomic_t<hb_aat_layout_chain_accelerator_t *> *accels;
|
||||
hb_aat_scratch_t scratch;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "hb-aat-layout-common.hh"
|
||||
#include "hb-ot-layout.hh"
|
||||
#include "hb-open-type.hh"
|
||||
#include "hb-ot-stat-table.hh"
|
||||
|
||||
/*
|
||||
* trak -- Tracking
|
||||
|
@ -115,7 +116,7 @@ struct TrackTableEntry
|
|||
|
||||
protected:
|
||||
F16DOT16 track; /* Track value for this record. */
|
||||
NameID trackNameID; /* The 'name' table index for this track.
|
||||
OT::NameID trackNameID; /* The 'name' table index for this track.
|
||||
* (a short word or phrase like "loose"
|
||||
* or "very tight") */
|
||||
NNOffset16To<UnsizedArrayOf<FWORD>>
|
||||
|
@ -142,9 +143,9 @@ struct TrackData
|
|||
unsigned j = count - 1;
|
||||
|
||||
// Find the two entries that track is between.
|
||||
while (i + 1 < count && trackTable[i + 1].get_track_value () < track)
|
||||
while (i + 1 < count && trackTable[i + 1].get_track_value () <= track)
|
||||
i++;
|
||||
while (j > 0 && trackTable[j - 1].get_track_value () > track)
|
||||
while (j > 0 && trackTable[j - 1].get_track_value () >= track)
|
||||
j--;
|
||||
|
||||
// Exact match.
|
||||
|
@ -200,6 +201,46 @@ struct trak
|
|||
float ptem = font->ptem > 0.f ? font->ptem : HB_CORETEXT_DEFAULT_FONT_SIZE;
|
||||
return font->em_scalef_y ((this+vertData).get_tracking (this, ptem, track));
|
||||
}
|
||||
hb_position_t get_tracking (hb_font_t *font, hb_direction_t dir, float track = 0.f) const
|
||||
{
|
||||
#ifndef HB_NO_STYLE
|
||||
if (!font->face->table.STAT->has_data ())
|
||||
return 0;
|
||||
return HB_DIRECTION_IS_HORIZONTAL (dir) ?
|
||||
get_h_tracking (font, track) :
|
||||
get_v_tracking (font, track);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool apply (hb_aat_apply_context_t *c, float track = 0.f) const
|
||||
{
|
||||
TRACE_APPLY (this);
|
||||
|
||||
float ptem = c->font->ptem;
|
||||
if (unlikely (ptem <= 0.f))
|
||||
{
|
||||
/* https://developer.apple.com/documentation/coretext/1508745-ctfontcreatewithgraphicsfont */
|
||||
ptem = HB_CORETEXT_DEFAULT_FONT_SIZE;
|
||||
}
|
||||
|
||||
hb_buffer_t *buffer = c->buffer;
|
||||
if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
|
||||
{
|
||||
hb_position_t advance_to_add = get_h_tracking (c->font, track);
|
||||
foreach_grapheme (buffer, start, end)
|
||||
buffer->pos[start].x_advance += advance_to_add;
|
||||
}
|
||||
else
|
||||
{
|
||||
hb_position_t advance_to_add = get_v_tracking (c->font, track);
|
||||
foreach_grapheme (buffer, start, end)
|
||||
buffer->pos[start].y_advance += advance_to_add;
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
#include "hb-aat-layout-just-table.hh" // Just so we compile it; unused otherwise.
|
||||
#include "hb-aat-layout-kerx-table.hh"
|
||||
#include "hb-aat-layout-morx-table.hh"
|
||||
#include "hb-aat-layout-trak-table.hh" // Just so we compile it; unused otherwise.
|
||||
#include "hb-aat-layout-trak-table.hh"
|
||||
#include "hb-aat-ltag-table.hh"
|
||||
|
||||
#include "hb-ot-layout-gsub-table.hh"
|
||||
|
@ -58,13 +58,14 @@ AAT::hb_aat_apply_context_t::hb_aat_apply_context_t (const hb_ot_shape_plan_t *p
|
|||
buffer (buffer_),
|
||||
sanitizer (),
|
||||
ankr_table (&Null (AAT::ankr)),
|
||||
gdef_table (
|
||||
gdef (
|
||||
#ifndef HB_NO_OT_LAYOUT
|
||||
face->table.GDEF->table
|
||||
*face->table.GDEF->table
|
||||
#else
|
||||
&Null (GDEF)
|
||||
Null (GDEF)
|
||||
#endif
|
||||
),
|
||||
has_glyph_classes (gdef.has_glyph_classes ()),
|
||||
lookup_index (0)
|
||||
{
|
||||
sanitizer.init (blob);
|
||||
|
@ -203,7 +204,7 @@ hb_aat_layout_find_feature_mapping (hb_tag_t tag)
|
|||
#endif
|
||||
|
||||
|
||||
#ifndef HB_NO_AAT
|
||||
#ifndef HB_NO_AAT_SHAPE
|
||||
|
||||
/*
|
||||
* mort/morx/kerx/trak
|
||||
|
@ -287,11 +288,14 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
|
|||
const hb_feature_t *features,
|
||||
unsigned num_features)
|
||||
{
|
||||
hb_aat_map_builder_t builder (font->face, plan->props);
|
||||
for (unsigned i = 0; i < num_features; i++)
|
||||
builder.add_feature (features[i]);
|
||||
hb_aat_map_t map;
|
||||
builder.compile (map);
|
||||
if (num_features)
|
||||
{
|
||||
hb_aat_map_builder_t builder (font->face, plan->props);
|
||||
for (unsigned i = 0; i < num_features; i++)
|
||||
builder.add_feature (features[i]);
|
||||
builder.compile (map);
|
||||
}
|
||||
|
||||
{
|
||||
auto &accel = *font->face->table.morx;
|
||||
|
@ -300,7 +304,10 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
|
|||
{
|
||||
AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ());
|
||||
if (!buffer->message (font, "start table morx")) return;
|
||||
morx.apply (&c, map, accel);
|
||||
c.buffer_glyph_set = accel.scratch.create_buffer_glyph_set ();
|
||||
morx.apply (&c, num_features ? map : plan->aat_map, accel);
|
||||
accel.scratch.destroy_buffer_glyph_set (c.buffer_glyph_set);
|
||||
c.buffer_glyph_set = nullptr;
|
||||
(void) buffer->message (font, "end table morx");
|
||||
return;
|
||||
}
|
||||
|
@ -313,34 +320,24 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
|
|||
{
|
||||
AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ());
|
||||
if (!buffer->message (font, "start table mort")) return;
|
||||
mort.apply (&c, map, accel);
|
||||
mort.apply (&c, num_features ? map : plan->aat_map, accel);
|
||||
(void) buffer->message (font, "end table mort");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
hb_aat_layout_zero_width_deleted_glyphs (hb_buffer_t *buffer)
|
||||
{
|
||||
unsigned int count = buffer->len;
|
||||
hb_glyph_info_t *info = buffer->info;
|
||||
hb_glyph_position_t *pos = buffer->pos;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (unlikely (info[i].codepoint == AAT::DELETED_GLYPH))
|
||||
pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
is_deleted_glyph (const hb_glyph_info_t *info)
|
||||
{
|
||||
return info->codepoint == AAT::DELETED_GLYPH;
|
||||
return _hb_glyph_info_is_aat_deleted (info);
|
||||
}
|
||||
|
||||
void
|
||||
hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer)
|
||||
{
|
||||
buffer->delete_glyphs_inplace (is_deleted_glyph);
|
||||
if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED)
|
||||
buffer->delete_glyphs_inplace (is_deleted_glyph);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -371,8 +368,11 @@ hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
|
|||
|
||||
AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ());
|
||||
if (!buffer->message (font, "start table kerx")) return;
|
||||
c.buffer_glyph_set = accel.scratch.create_buffer_glyph_set ();
|
||||
c.set_ankr_table (font->face->table.ankr.get ());
|
||||
accel.apply (&c);
|
||||
accel.scratch.destroy_buffer_glyph_set (c.buffer_glyph_set);
|
||||
c.buffer_glyph_set = nullptr;
|
||||
(void) buffer->message (font, "end table kerx");
|
||||
}
|
||||
|
||||
|
@ -394,6 +394,17 @@ hb_aat_layout_has_tracking (hb_face_t *face)
|
|||
return face->table.trak->has_data ();
|
||||
}
|
||||
|
||||
void
|
||||
hb_aat_layout_track (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer)
|
||||
{
|
||||
const AAT::trak& trak = *font->face->table.trak;
|
||||
|
||||
AAT::hb_aat_apply_context_t c (plan, font, buffer);
|
||||
trak.apply (&c);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_aat_layout_get_feature_types:
|
||||
* @face: #hb_face_t to work upon
|
||||
|
|
|
@ -60,9 +60,6 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
|
|||
const hb_feature_t *features,
|
||||
unsigned num_features);
|
||||
|
||||
HB_INTERNAL void
|
||||
hb_aat_layout_zero_width_deleted_glyphs (hb_buffer_t *buffer);
|
||||
|
||||
HB_INTERNAL void
|
||||
hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer);
|
||||
|
||||
|
@ -71,5 +68,10 @@ hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
|
|||
hb_font_t *font,
|
||||
hb_buffer_t *buffer);
|
||||
|
||||
HB_INTERNAL void
|
||||
hb_aat_layout_track (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer);
|
||||
|
||||
|
||||
#endif /* HB_AAT_LAYOUT_HH */
|
||||
|
|
|
@ -85,6 +85,11 @@ void
|
|||
hb_aat_map_builder_t::compile (hb_aat_map_t &m)
|
||||
{
|
||||
/* Compute active features per range, and compile each. */
|
||||
if (!features.length)
|
||||
{
|
||||
hb_aat_layout_compile_map (this, &m);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Sort features by start/end events. */
|
||||
hb_vector_t<feature_event_t> feature_events;
|
||||
|
|
|
@ -80,15 +80,14 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
|
|||
|
||||
#include <atomic>
|
||||
|
||||
#define _hb_memory_barrier() std::atomic_thread_fence(std::memory_order_ack_rel)
|
||||
#define _hb_memory_r_barrier() std::atomic_thread_fence(std::memory_order_acquire)
|
||||
#define _hb_memory_w_barrier() std::atomic_thread_fence(std::memory_order_release)
|
||||
|
||||
#define hb_atomic_int_impl_add(AI, V) (reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> *> (AI)->fetch_add ((V), std::memory_order_acq_rel))
|
||||
#define hb_atomic_int_impl_set_relaxed(AI, V) (reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> *> (AI)->store ((V), std::memory_order_relaxed))
|
||||
#define hb_atomic_int_impl_set(AI, V) (reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> *> (AI)->store ((V), std::memory_order_release))
|
||||
#define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> const *> (AI)->load (std::memory_order_relaxed))
|
||||
#define hb_atomic_int_impl_get(AI) (reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> const *> (AI)->load (std::memory_order_acquire))
|
||||
#define hb_atomic_int_impl_add(AI, V) (reinterpret_cast<std::atomic<typename std::decay<decltype (*(AI))>::type> *> (AI)->fetch_add ((V), std::memory_order_acq_rel))
|
||||
#define hb_atomic_int_impl_set_relaxed(AI, V) (reinterpret_cast<std::atomic<typename std::decay<decltype (*(AI))>::type> *> (AI)->store ((V), std::memory_order_relaxed))
|
||||
#define hb_atomic_int_impl_set(AI, V) (reinterpret_cast<std::atomic<typename std::decay<decltype (*(AI))>::type> *> (AI)->store ((V), std::memory_order_release))
|
||||
#define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast<std::atomic<typename std::decay<decltype (*(AI))>::type> const *> (AI)->load (std::memory_order_relaxed))
|
||||
#define hb_atomic_int_impl_get(AI) (reinterpret_cast<std::atomic<typename std::decay<decltype (*(AI))>::type> const *> (AI)->load (std::memory_order_acquire))
|
||||
|
||||
#define hb_atomic_ptr_impl_set_relaxed(P, V) (reinterpret_cast<std::atomic<void*> *> (P)->store ((V), std::memory_order_relaxed))
|
||||
#define hb_atomic_ptr_impl_get_relaxed(P) (reinterpret_cast<std::atomic<void*> const *> (P)->load (std::memory_order_relaxed))
|
||||
|
@ -149,62 +148,47 @@ static inline void _hb_compiler_memory_r_barrier () {}
|
|||
#define hb_atomic_ptr_impl_get_relaxed(P) (*(P))
|
||||
#endif
|
||||
#ifndef hb_atomic_int_impl_set
|
||||
inline void hb_atomic_int_impl_set (int *AI, int v) { _hb_memory_w_barrier (); *AI = v; }
|
||||
inline void hb_atomic_int_impl_set (short *AI, short v) { _hb_memory_w_barrier (); *AI = v; }
|
||||
template <typename T>
|
||||
inline void hb_atomic_int_impl_set (T *AI, T v) { _hb_memory_w_barrier (); *AI = v; }
|
||||
#endif
|
||||
#ifndef hb_atomic_int_impl_get
|
||||
inline int hb_atomic_int_impl_get (const int *AI) { int v = *AI; _hb_memory_r_barrier (); return v; }
|
||||
inline short hb_atomic_int_impl_get (const short *AI) { short v = *AI; _hb_memory_r_barrier (); return v; }
|
||||
template <typename T>
|
||||
inline T hb_atomic_int_impl_get (const T *AI) { T v = *AI; _hb_memory_r_barrier (); return v; }
|
||||
#endif
|
||||
#ifndef hb_atomic_ptr_impl_get
|
||||
inline void *hb_atomic_ptr_impl_get (void ** const P) { void *v = *P; _hb_memory_r_barrier (); return v; }
|
||||
#endif
|
||||
|
||||
|
||||
struct hb_atomic_short_t
|
||||
template <typename T>
|
||||
struct hb_atomic_t
|
||||
{
|
||||
hb_atomic_short_t () = default;
|
||||
constexpr hb_atomic_short_t (short v) : v (v) {}
|
||||
hb_atomic_t () = default;
|
||||
constexpr hb_atomic_t (T v) : v (v) {}
|
||||
|
||||
hb_atomic_short_t& operator = (short v_) { set_relaxed (v_); return *this; }
|
||||
operator short () const { return get_relaxed (); }
|
||||
hb_atomic_t& operator = (T v_) { set_relaxed (v_); return *this; }
|
||||
operator T () const { return get_relaxed (); }
|
||||
|
||||
void set_relaxed (short v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
|
||||
void set_release (short v_) { hb_atomic_int_impl_set (&v, v_); }
|
||||
short get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); }
|
||||
short get_acquire () const { return hb_atomic_int_impl_get (&v); }
|
||||
short inc () { return hb_atomic_int_impl_add (&v, 1); }
|
||||
short dec () { return hb_atomic_int_impl_add (&v, -1); }
|
||||
void set_relaxed (T v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
|
||||
void set_release (T v_) { hb_atomic_int_impl_set (&v, v_); }
|
||||
T get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); }
|
||||
T get_acquire () const { return hb_atomic_int_impl_get (&v); }
|
||||
T inc () { return hb_atomic_int_impl_add (&v, 1); }
|
||||
T dec () { return hb_atomic_int_impl_add (&v, -1); }
|
||||
|
||||
short v = 0;
|
||||
int operator ++ (int) { return inc (); }
|
||||
int operator -- (int) { return dec (); }
|
||||
long operator |= (long v_) { set_relaxed (get_relaxed () | v_); return *this; }
|
||||
|
||||
T v = 0;
|
||||
};
|
||||
|
||||
struct hb_atomic_int_t
|
||||
template <typename T>
|
||||
struct hb_atomic_t<T*>
|
||||
{
|
||||
hb_atomic_int_t () = default;
|
||||
constexpr hb_atomic_int_t (int v) : v (v) {}
|
||||
|
||||
hb_atomic_int_t& operator = (int v_) { set_relaxed (v_); return *this; }
|
||||
operator int () const { return get_relaxed (); }
|
||||
|
||||
void set_relaxed (int v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
|
||||
void set_release (int v_) { hb_atomic_int_impl_set (&v, v_); }
|
||||
int get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); }
|
||||
int get_acquire () const { return hb_atomic_int_impl_get (&v); }
|
||||
int inc () { return hb_atomic_int_impl_add (&v, 1); }
|
||||
int dec () { return hb_atomic_int_impl_add (&v, -1); }
|
||||
|
||||
int v = 0;
|
||||
};
|
||||
|
||||
template <typename P>
|
||||
struct hb_atomic_ptr_t
|
||||
{
|
||||
typedef hb_remove_pointer<P> T;
|
||||
|
||||
hb_atomic_ptr_t () = default;
|
||||
constexpr hb_atomic_ptr_t (T* v) : v (v) {}
|
||||
hb_atomic_ptr_t (const hb_atomic_ptr_t &other) = delete;
|
||||
hb_atomic_t () = default;
|
||||
constexpr hb_atomic_t (T* v) : v (v) {}
|
||||
hb_atomic_t (const hb_atomic_t &other) = delete;
|
||||
|
||||
void init (T* v_ = nullptr) { set_relaxed (v_); }
|
||||
void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); }
|
||||
|
|
|
@ -77,7 +77,7 @@ struct hb_bit_set_t
|
|||
|
||||
bool successful = true; /* Allocations successful */
|
||||
mutable unsigned int population = 0;
|
||||
mutable hb_atomic_int_t last_page_lookup = 0;
|
||||
mutable hb_atomic_t<unsigned> last_page_lookup = 0;
|
||||
hb_sorted_vector_t<page_map_t> page_map;
|
||||
hb_vector_t<page_t> pages;
|
||||
|
||||
|
@ -88,7 +88,7 @@ struct hb_bit_set_t
|
|||
{
|
||||
if (unlikely (!successful)) return false;
|
||||
|
||||
if (pages.length < count && count <= 2)
|
||||
if (pages.length < count && (unsigned) pages.allocated < count && count <= 2)
|
||||
exact_size = true; // Most sets are small and local
|
||||
|
||||
if (unlikely (!pages.resize (count, clear, exact_size) ||
|
||||
|
|
195
src/hb-bit-vector.hh
Normal file
195
src/hb-bit-vector.hh
Normal file
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_BIT_VECTOR_HH
|
||||
#define HB_BIT_VECTOR_HH
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#include "hb-atomic.hh"
|
||||
|
||||
struct hb_min_max_t
|
||||
{
|
||||
void add (hb_codepoint_t v) { min_v = hb_min (min_v, v); max_v = hb_max (max_v, v); }
|
||||
void add_range (hb_codepoint_t a, hb_codepoint_t b)
|
||||
{
|
||||
min_v = hb_min (min_v, a);
|
||||
max_v = hb_max (max_v, b);
|
||||
}
|
||||
|
||||
template <typename set_t>
|
||||
void union_ (const set_t &set)
|
||||
{
|
||||
hb_codepoint_t set_min = set.get_min ();
|
||||
if (unlikely (set_min == HB_CODEPOINT_INVALID))
|
||||
return;
|
||||
hb_codepoint_t set_max = set.get_max ();
|
||||
min_v = hb_min (min_v, set_min);
|
||||
max_v = hb_max (max_v, set_max);
|
||||
}
|
||||
|
||||
hb_codepoint_t get_min () const { return min_v; }
|
||||
hb_codepoint_t get_max () const { return max_v; }
|
||||
|
||||
private:
|
||||
hb_codepoint_t min_v = HB_CODEPOINT_INVALID;
|
||||
hb_codepoint_t max_v = 0;
|
||||
};
|
||||
|
||||
template <bool atomic = false>
|
||||
struct hb_bit_vector_t
|
||||
{
|
||||
using int_t = uint64_t;
|
||||
using elt_t = typename std::conditional<atomic, hb_atomic_t<int_t>, int_t>::type;
|
||||
|
||||
hb_bit_vector_t () = delete;
|
||||
hb_bit_vector_t (const hb_bit_vector_t &other) = delete;
|
||||
hb_bit_vector_t &operator= (const hb_bit_vector_t &other) = delete;
|
||||
|
||||
// Move
|
||||
hb_bit_vector_t (hb_bit_vector_t &&other)
|
||||
: min_v (other.min_v), max_v (other.max_v), count (other.count), elts (other.elts)
|
||||
{
|
||||
other.min_v = other.max_v = other.count = 0;
|
||||
other.elts = nullptr;
|
||||
}
|
||||
hb_bit_vector_t &operator= (hb_bit_vector_t &&other)
|
||||
{
|
||||
hb_swap (min_v, other.min_v);
|
||||
hb_swap (max_v, other.max_v);
|
||||
hb_swap (count, other.count);
|
||||
hb_swap (elts, other.elts);
|
||||
return *this;
|
||||
}
|
||||
|
||||
hb_bit_vector_t (unsigned min_v, unsigned max_v)
|
||||
: min_v (min_v), max_v (max_v)
|
||||
{
|
||||
if (unlikely (min_v >= max_v))
|
||||
{
|
||||
min_v = max_v = count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned num = (max_v - min_v + sizeof (int_t) * 8) / (sizeof (int_t) * 8);
|
||||
elts = (elt_t *) hb_calloc (num, sizeof (int_t));
|
||||
if (unlikely (!elts))
|
||||
{
|
||||
min_v = max_v = count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
count = max_v - min_v + 1;
|
||||
}
|
||||
~hb_bit_vector_t ()
|
||||
{
|
||||
hb_free (elts);
|
||||
}
|
||||
|
||||
void add (hb_codepoint_t g) { elt (g) |= mask (g); }
|
||||
void del (hb_codepoint_t g) { elt (g) &= ~mask (g); }
|
||||
void set (hb_codepoint_t g, bool value) { if (value) add (g); else del (g); }
|
||||
bool get (hb_codepoint_t g) const { return elt (g) & mask (g); }
|
||||
bool has (hb_codepoint_t g) const { return get (g); }
|
||||
bool may_have (hb_codepoint_t g) const { return get (g); }
|
||||
|
||||
bool operator [] (hb_codepoint_t g) const { return get (g); }
|
||||
bool operator () (hb_codepoint_t g) const { return get (g); }
|
||||
|
||||
void add_range (hb_codepoint_t a, hb_codepoint_t b)
|
||||
{
|
||||
if (unlikely (!count || a > b || a < min_v || b > max_v))
|
||||
return;
|
||||
|
||||
elt_t *la = &elt (a);
|
||||
elt_t *lb = &elt (b);
|
||||
if (la == lb)
|
||||
*la |= (mask (b) << 1) - mask(a);
|
||||
else
|
||||
{
|
||||
*la |= ~(mask (a) - 1llu);
|
||||
la++;
|
||||
|
||||
hb_memset (la, 0xff, (char *) lb - (char *) la);
|
||||
|
||||
*lb |= ((mask (b) << 1) - 1llu);
|
||||
}
|
||||
}
|
||||
void del_range (hb_codepoint_t a, hb_codepoint_t b)
|
||||
{
|
||||
if (unlikely (!count || a > b || a < min_v || b > max_v))
|
||||
return;
|
||||
|
||||
elt_t *la = &elt (a);
|
||||
elt_t *lb = &elt (b);
|
||||
if (la == lb)
|
||||
*la &= ~((mask (b) << 1llu) - mask(a));
|
||||
else
|
||||
{
|
||||
*la &= mask (a) - 1;
|
||||
la++;
|
||||
|
||||
hb_memset (la, 0, (char *) lb - (char *) la);
|
||||
|
||||
*lb &= ~((mask (b) << 1) - 1llu);
|
||||
}
|
||||
}
|
||||
void set_range (hb_codepoint_t a, hb_codepoint_t b, bool v)
|
||||
{ if (v) add_range (a, b); else del_range (a, b); }
|
||||
|
||||
template <typename set_t>
|
||||
void union_ (const set_t &set)
|
||||
{
|
||||
for (hb_codepoint_t g : set)
|
||||
add (g);
|
||||
}
|
||||
|
||||
static const unsigned int ELT_BITS = sizeof (elt_t) * 8;
|
||||
static constexpr unsigned ELT_MASK = ELT_BITS - 1;
|
||||
|
||||
static constexpr elt_t zero = 0;
|
||||
|
||||
elt_t &elt (hb_codepoint_t g)
|
||||
{
|
||||
g -= min_v;
|
||||
if (unlikely (g >= count))
|
||||
return Crap(elt_t);
|
||||
return elts[g / ELT_BITS];
|
||||
}
|
||||
const elt_t& elt (hb_codepoint_t g) const
|
||||
{
|
||||
g -= min_v;
|
||||
if (unlikely (g >= count))
|
||||
return Null(elt_t);
|
||||
return elts[g / ELT_BITS];
|
||||
}
|
||||
|
||||
static constexpr int_t mask (hb_codepoint_t g) { return elt_t (1) << (g & ELT_MASK); }
|
||||
|
||||
hb_codepoint_t min_v = 0, max_v = 0, count = 0;
|
||||
elt_t *elts = nullptr;
|
||||
};
|
||||
|
||||
|
||||
#endif /* HB_BIT_VECTOR_HH */
|
File diff suppressed because it is too large
Load diff
|
@ -91,6 +91,8 @@ yoffset = "\"dy\"" colon (num >tok %parse_y_offset);
|
|||
xadvance= "\"ax\"" colon (num >tok %parse_x_advance);
|
||||
yadvance= "\"ay\"" colon (num >tok %parse_y_advance);
|
||||
glyphflags="\"fl\"" colon (unum >tok %parse_glyph_flags);
|
||||
# Not parsed. Ignored.
|
||||
glyphextents="\""("xb"|"yb"|"w"|"h")"\"" colon (num >tok);
|
||||
|
||||
element = glyph @ensure_glyphs
|
||||
| unicode @ensure_unicode
|
||||
|
@ -99,14 +101,16 @@ element = glyph @ensure_glyphs
|
|||
| yoffset
|
||||
| xadvance
|
||||
| yadvance
|
||||
| glyphflags;
|
||||
| glyphflags
|
||||
| glyphextents
|
||||
;
|
||||
item =
|
||||
( '{' space* element (comma element)* space* '}')
|
||||
( '{' space* element (comma element)* space* '}' space* (','|']') space* )
|
||||
>clear_item
|
||||
@add_item
|
||||
;
|
||||
|
||||
main := space* '['? space* item (comma item)* space* (','|']')?;
|
||||
main := space* '['? space* item*;
|
||||
|
||||
}%%
|
||||
|
||||
|
@ -133,7 +137,7 @@ _hb_buffer_deserialize_json (hb_buffer_t *buffer,
|
|||
|
||||
*end_ptr = p;
|
||||
|
||||
return p == pe && *(p-1) != ']';
|
||||
return p == pe;
|
||||
}
|
||||
|
||||
#endif /* HB_BUFFER_DESERIALIZE_JSON_HH */
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -41,10 +41,9 @@ action clear_item {
|
|||
}
|
||||
|
||||
action add_item {
|
||||
buffer->add_info (info);
|
||||
buffer->add_info_and_pos (info, pos);
|
||||
if (unlikely (!buffer->successful))
|
||||
return false;
|
||||
buffer->pos[buffer->len - 1] = pos;
|
||||
*end_ptr = p;
|
||||
}
|
||||
|
||||
|
@ -77,7 +76,9 @@ glyph = (glyph_id | glyph_name) >tok %parse_glyph;
|
|||
cluster = '=' (unum >tok %parse_cluster);
|
||||
offsets = '@' (num >tok %parse_x_offset) ',' (num >tok %parse_y_offset );
|
||||
advances= '+' (num >tok %parse_x_advance) (',' (num >tok %parse_y_advance))?;
|
||||
glyphflags= '#' (unum >tok %parse_glyph_flags);
|
||||
glyphflags = '#' (unum >tok %parse_glyph_flags);
|
||||
# Not parsed. Ignored.
|
||||
glyphextents = '<' (num ',' num ',' num ',' num) '>';
|
||||
|
||||
glyph_item =
|
||||
(
|
||||
|
@ -86,14 +87,16 @@ glyph_item =
|
|||
offsets?
|
||||
advances?
|
||||
glyphflags?
|
||||
glyphextents?
|
||||
( '|' | ']')
|
||||
)
|
||||
>clear_item
|
||||
%add_item
|
||||
;
|
||||
|
||||
glyphs = glyph_item (space* '|' space* glyph_item)* space*;
|
||||
glyphs = '['? glyph_item* ;
|
||||
|
||||
main := space* glyphs;
|
||||
main := glyphs;
|
||||
|
||||
}%%
|
||||
|
||||
|
@ -104,28 +107,11 @@ _hb_buffer_deserialize_text_glyphs (hb_buffer_t *buffer,
|
|||
const char **end_ptr,
|
||||
hb_font_t *font)
|
||||
{
|
||||
const char *p = buf, *pe = buf + buf_len, *eof = pe, *orig_pe = pe;
|
||||
const char *p = buf, *pe = buf + buf_len, *eof = pe;
|
||||
|
||||
/* Ensure we have positions. */
|
||||
(void) hb_buffer_get_glyph_positions (buffer, nullptr);
|
||||
|
||||
while (p < pe && ISSPACE (*p))
|
||||
p++;
|
||||
if (p < pe && *p == (buffer->len ? '|' : '['))
|
||||
*end_ptr = ++p;
|
||||
|
||||
const char *end = strchr ((char *) p, ']');
|
||||
if (end)
|
||||
pe = eof = end;
|
||||
else
|
||||
{
|
||||
end = strrchr ((char *) p, '|');
|
||||
if (end)
|
||||
pe = eof = end;
|
||||
else
|
||||
pe = eof = p;
|
||||
}
|
||||
|
||||
const char *tok = nullptr;
|
||||
int cs;
|
||||
hb_glyph_info_t info = {0};
|
||||
|
@ -135,13 +121,6 @@ _hb_buffer_deserialize_text_glyphs (hb_buffer_t *buffer,
|
|||
write exec;
|
||||
}%%
|
||||
|
||||
if (pe < orig_pe && *pe == ']')
|
||||
{
|
||||
pe++;
|
||||
if (p == pe)
|
||||
p++;
|
||||
}
|
||||
|
||||
*end_ptr = p;
|
||||
|
||||
return p == pe;
|
||||
|
|
|
@ -34,135 +34,106 @@
|
|||
|
||||
#line 36 "hb-buffer-deserialize-text-unicode.hh"
|
||||
static const unsigned char _deserialize_text_unicode_trans_keys[] = {
|
||||
0u, 0u, 9u, 117u, 43u, 102u, 48u, 102u, 48u, 57u, 9u, 124u, 9u, 124u, 9u, 124u,
|
||||
9u, 124u, 0
|
||||
0u, 0u, 43u, 102u, 48u, 102u, 48u, 124u, 48u, 57u, 62u, 124u, 48u, 124u, 60u, 117u,
|
||||
85u, 117u, 85u, 117u, 0
|
||||
};
|
||||
|
||||
static const char _deserialize_text_unicode_key_spans[] = {
|
||||
0, 109, 60, 55, 10, 116, 116, 116,
|
||||
116
|
||||
0, 60, 55, 77, 10, 63, 77, 58,
|
||||
33, 33
|
||||
};
|
||||
|
||||
static const short _deserialize_text_unicode_index_offsets[] = {
|
||||
0, 0, 110, 171, 227, 238, 355, 472,
|
||||
589
|
||||
0, 0, 61, 117, 195, 206, 270, 348,
|
||||
407, 441
|
||||
};
|
||||
|
||||
static const char _deserialize_text_unicode_indicies[] = {
|
||||
0, 0, 0, 0, 0, 1, 1,
|
||||
0, 1, 1, 1, 1, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2,
|
||||
1, 1, 1, 1, 1, 1, 1, 2,
|
||||
2, 2, 2, 2, 2, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
0, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 2,
|
||||
2, 2, 2, 2, 2, 1, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2,
|
||||
1, 1, 1, 1, 1, 1, 1, 2,
|
||||
2, 2, 2, 2, 2, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 2,
|
||||
2, 2, 2, 2, 2, 1, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3,
|
||||
1, 1, 1, 4, 5, 1, 1, 3,
|
||||
3, 3, 3, 3, 3, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 3,
|
||||
3, 3, 3, 3, 3, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 5, 1, 6, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 1, 8,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 2, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 8, 1, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 9,
|
||||
9, 1, 1, 1, 1, 8, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 2, 1, 3,
|
||||
1, 1, 1, 1, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 1, 1,
|
||||
1, 1, 1, 1, 1, 4, 4, 4,
|
||||
4, 4, 4, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 4, 4, 4,
|
||||
4, 4, 4, 1, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 1, 1,
|
||||
1, 1, 1, 1, 1, 4, 4, 4,
|
||||
4, 4, 4, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 4, 4, 4,
|
||||
4, 4, 4, 1, 5, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 1, 7,
|
||||
7, 7, 7, 7, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 7, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 8, 8,
|
||||
8, 8, 8, 8, 8, 8, 8, 8,
|
||||
1, 1, 1, 9, 1, 1, 1, 8,
|
||||
8, 8, 8, 8, 8, 1, 1, 1,
|
||||
1, 1, 1, 8, 1, 10, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 8,
|
||||
8, 8, 8, 8, 8, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 11, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 10, 1, 11, 11, 11, 11,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 11, 1,
|
||||
11, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 11, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
11, 1, 12, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 0,
|
||||
1, 12, 12, 12, 12, 12, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
12, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 13, 1, 12, 12,
|
||||
12, 12, 12, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 12, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 14, 14, 14,
|
||||
14, 14, 14, 14, 14, 14, 14, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 13, 1, 0
|
||||
1, 1, 12, 1, 0
|
||||
};
|
||||
|
||||
static const char _deserialize_text_unicode_trans_targs[] = {
|
||||
1, 0, 2, 3, 5, 7, 8, 6,
|
||||
5, 4, 1, 6, 6, 1, 8
|
||||
2, 0, 3, 3, 4, 9, 5, 6,
|
||||
9, 6, 8, 1, 1
|
||||
};
|
||||
|
||||
static const char _deserialize_text_unicode_trans_actions[] = {
|
||||
0, 0, 1, 0, 2, 2, 2, 3,
|
||||
0, 4, 3, 0, 5, 5, 0
|
||||
0, 0, 1, 0, 2, 2, 1, 1,
|
||||
3, 0, 0, 4, 6
|
||||
};
|
||||
|
||||
static const char _deserialize_text_unicode_eof_actions[] = {
|
||||
0, 0, 0, 0, 0, 3, 0, 5,
|
||||
5
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 5
|
||||
};
|
||||
|
||||
static const int deserialize_text_unicode_start = 1;
|
||||
static const int deserialize_text_unicode_first_final = 5;
|
||||
static const int deserialize_text_unicode_start = 7;
|
||||
static const int deserialize_text_unicode_first_final = 7;
|
||||
static const int deserialize_text_unicode_error = 0;
|
||||
|
||||
static const int deserialize_text_unicode_en_main = 1;
|
||||
static const int deserialize_text_unicode_en_main = 7;
|
||||
|
||||
|
||||
#line 79 "hb-buffer-deserialize-text-unicode.rl"
|
||||
#line 80 "hb-buffer-deserialize-text-unicode.rl"
|
||||
|
||||
|
||||
static hb_bool_t
|
||||
|
@ -172,37 +143,19 @@ _hb_buffer_deserialize_text_unicode (hb_buffer_t *buffer,
|
|||
const char **end_ptr,
|
||||
hb_font_t *font)
|
||||
{
|
||||
const char *p = buf, *pe = buf + buf_len, *eof = pe, *orig_pe = pe;
|
||||
|
||||
while (p < pe && ISSPACE (*p))
|
||||
p++;
|
||||
if (p < pe && *p == (buffer->len ? '|' : '<'))
|
||||
*end_ptr = ++p;
|
||||
|
||||
const char *end = strchr ((char *) p, '>');
|
||||
if (end)
|
||||
pe = eof = end;
|
||||
else
|
||||
{
|
||||
end = strrchr ((char *) p, '|');
|
||||
if (end)
|
||||
pe = eof = end;
|
||||
else
|
||||
pe = eof = p;
|
||||
}
|
||||
|
||||
const char *p = buf, *pe = buf + buf_len, *eof = pe;
|
||||
|
||||
const char *tok = nullptr;
|
||||
int cs;
|
||||
hb_glyph_info_t info = {0};
|
||||
const hb_glyph_position_t pos = {0};
|
||||
|
||||
#line 201 "hb-buffer-deserialize-text-unicode.hh"
|
||||
#line 154 "hb-buffer-deserialize-text-unicode.hh"
|
||||
{
|
||||
cs = deserialize_text_unicode_start;
|
||||
}
|
||||
|
||||
#line 206 "hb-buffer-deserialize-text-unicode.hh"
|
||||
#line 159 "hb-buffer-deserialize-text-unicode.hh"
|
||||
{
|
||||
int _slen;
|
||||
int _trans;
|
||||
|
@ -227,38 +180,27 @@ _resume:
|
|||
goto _again;
|
||||
|
||||
switch ( _deserialize_text_unicode_trans_actions[_trans] ) {
|
||||
case 1:
|
||||
case 4:
|
||||
#line 38 "hb-buffer-deserialize-text-unicode.rl"
|
||||
{
|
||||
hb_memset (&info, 0, sizeof (info));
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
case 1:
|
||||
#line 51 "hb-buffer-deserialize-text-unicode.rl"
|
||||
{
|
||||
tok = p;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
case 2:
|
||||
#line 55 "hb-buffer-deserialize-text-unicode.rl"
|
||||
{if (!parse_hex (tok, p, &info.codepoint )) return false; }
|
||||
break;
|
||||
case 3:
|
||||
#line 55 "hb-buffer-deserialize-text-unicode.rl"
|
||||
{if (!parse_hex (tok, p, &info.codepoint )) return false; }
|
||||
#line 42 "hb-buffer-deserialize-text-unicode.rl"
|
||||
{
|
||||
buffer->add_info (info);
|
||||
if (unlikely (!buffer->successful))
|
||||
return false;
|
||||
if (buffer->have_positions)
|
||||
buffer->pos[buffer->len - 1] = pos;
|
||||
*end_ptr = p;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
#line 57 "hb-buffer-deserialize-text-unicode.rl"
|
||||
{ if (!parse_uint (tok, p, &info.cluster )) return false; }
|
||||
break;
|
||||
case 6:
|
||||
#line 42 "hb-buffer-deserialize-text-unicode.rl"
|
||||
{
|
||||
buffer->add_info (info);
|
||||
|
@ -267,9 +209,13 @@ _resume:
|
|||
if (buffer->have_positions)
|
||||
buffer->pos[buffer->len - 1] = pos;
|
||||
*end_ptr = p;
|
||||
}
|
||||
#line 38 "hb-buffer-deserialize-text-unicode.rl"
|
||||
{
|
||||
hb_memset (&info, 0, sizeof (info));
|
||||
}
|
||||
break;
|
||||
#line 273 "hb-buffer-deserialize-text-unicode.hh"
|
||||
#line 219 "hb-buffer-deserialize-text-unicode.hh"
|
||||
}
|
||||
|
||||
_again:
|
||||
|
@ -281,22 +227,7 @@ _again:
|
|||
if ( p == eof )
|
||||
{
|
||||
switch ( _deserialize_text_unicode_eof_actions[cs] ) {
|
||||
case 3:
|
||||
#line 55 "hb-buffer-deserialize-text-unicode.rl"
|
||||
{if (!parse_hex (tok, p, &info.codepoint )) return false; }
|
||||
#line 42 "hb-buffer-deserialize-text-unicode.rl"
|
||||
{
|
||||
buffer->add_info (info);
|
||||
if (unlikely (!buffer->successful))
|
||||
return false;
|
||||
if (buffer->have_positions)
|
||||
buffer->pos[buffer->len - 1] = pos;
|
||||
*end_ptr = p;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
#line 57 "hb-buffer-deserialize-text-unicode.rl"
|
||||
{ if (!parse_uint (tok, p, &info.cluster )) return false; }
|
||||
#line 42 "hb-buffer-deserialize-text-unicode.rl"
|
||||
{
|
||||
buffer->add_info (info);
|
||||
|
@ -307,23 +238,16 @@ _again:
|
|||
*end_ptr = p;
|
||||
}
|
||||
break;
|
||||
#line 311 "hb-buffer-deserialize-text-unicode.hh"
|
||||
#line 242 "hb-buffer-deserialize-text-unicode.hh"
|
||||
}
|
||||
}
|
||||
|
||||
_out: {}
|
||||
}
|
||||
|
||||
#line 115 "hb-buffer-deserialize-text-unicode.rl"
|
||||
#line 98 "hb-buffer-deserialize-text-unicode.rl"
|
||||
|
||||
|
||||
if (pe < orig_pe && *pe == '>')
|
||||
{
|
||||
pe++;
|
||||
if (p == pe)
|
||||
p++;
|
||||
}
|
||||
|
||||
*end_ptr = p;
|
||||
|
||||
return p == pe;
|
||||
|
|
|
@ -67,14 +67,15 @@ unicode_item =
|
|||
(
|
||||
unicode
|
||||
cluster?
|
||||
('|' | '>')
|
||||
)
|
||||
>clear_item
|
||||
%add_item
|
||||
;
|
||||
|
||||
unicodes = unicode_item (space* '|' space* unicode_item)* space*;
|
||||
unicodes = '<'? unicode_item*;
|
||||
|
||||
main := space* unicodes;
|
||||
main := unicodes;
|
||||
|
||||
}%%
|
||||
|
||||
|
@ -85,25 +86,7 @@ _hb_buffer_deserialize_text_unicode (hb_buffer_t *buffer,
|
|||
const char **end_ptr,
|
||||
hb_font_t *font)
|
||||
{
|
||||
const char *p = buf, *pe = buf + buf_len, *eof = pe, *orig_pe = pe;
|
||||
|
||||
while (p < pe && ISSPACE (*p))
|
||||
p++;
|
||||
if (p < pe && *p == (buffer->len ? '|' : '<'))
|
||||
*end_ptr = ++p;
|
||||
|
||||
const char *end = strchr ((char *) p, '>');
|
||||
if (end)
|
||||
pe = eof = end;
|
||||
else
|
||||
{
|
||||
end = strrchr ((char *) p, '|');
|
||||
if (end)
|
||||
pe = eof = end;
|
||||
else
|
||||
pe = eof = p;
|
||||
}
|
||||
|
||||
const char *p = buf, *pe = buf + buf_len, *eof = pe;
|
||||
|
||||
const char *tok = nullptr;
|
||||
int cs;
|
||||
|
@ -114,13 +97,6 @@ _hb_buffer_deserialize_text_unicode (hb_buffer_t *buffer,
|
|||
write exec;
|
||||
}%%
|
||||
|
||||
if (pe < orig_pe && *pe == '>')
|
||||
{
|
||||
pe++;
|
||||
if (p == pe)
|
||||
p++;
|
||||
}
|
||||
|
||||
*end_ptr = p;
|
||||
|
||||
return p == pe;
|
||||
|
|
|
@ -169,11 +169,13 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
|
|||
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
|
||||
{
|
||||
hb_glyph_extents_t extents;
|
||||
hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
|
||||
extents.x_bearing, extents.y_bearing));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
|
||||
extents.width, extents.height));
|
||||
if (hb_font_get_glyph_extents(font, info[i].codepoint, &extents))
|
||||
{
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
|
||||
extents.x_bearing, extents.y_bearing));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
|
||||
extents.width, extents.height));
|
||||
}
|
||||
}
|
||||
|
||||
*p++ = '}';
|
||||
|
@ -318,8 +320,8 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
|
|||
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
|
||||
{
|
||||
hb_glyph_extents_t extents;
|
||||
hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
|
||||
if (hb_font_get_glyph_extents(font, info[i].codepoint, &extents))
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
|
||||
}
|
||||
|
||||
if (i == end-1) {
|
||||
|
@ -737,8 +739,7 @@ parse_hex (const char *pp, const char *end, uint32_t *pv)
|
|||
* Deserializes glyphs @buffer from textual representation in the format
|
||||
* produced by hb_buffer_serialize_glyphs().
|
||||
*
|
||||
* Return value: `true` if parse was successful, `false` if an error
|
||||
* occurred.
|
||||
* Return value: `true` if the full string was parsed, `false` otherwise.
|
||||
*
|
||||
* Since: 0.9.7
|
||||
**/
|
||||
|
@ -810,8 +811,7 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
|
|||
* Deserializes Unicode @buffer from textual representation in the format
|
||||
* produced by hb_buffer_serialize_unicode().
|
||||
*
|
||||
* Return value: `true` if parse was successful, `false` if an error
|
||||
* occurred.
|
||||
* Return value: `true` if the full string was parsed, `false` otherwise.
|
||||
*
|
||||
* Since: 2.7.3
|
||||
**/
|
||||
|
|
|
@ -63,24 +63,25 @@ static bool
|
|||
buffer_verify_monotone (hb_buffer_t *buffer,
|
||||
hb_font_t *font)
|
||||
{
|
||||
/* Check that clusters are monotone. */
|
||||
if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES ||
|
||||
buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
|
||||
if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (buffer->cluster_level))
|
||||
{
|
||||
bool is_forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));
|
||||
|
||||
unsigned int num_glyphs;
|
||||
hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
|
||||
|
||||
for (unsigned int i = 1; i < num_glyphs; i++)
|
||||
if (info[i-1].cluster != info[i].cluster &&
|
||||
(info[i-1].cluster < info[i].cluster) != is_forward)
|
||||
{
|
||||
buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "clusters are not monotone.");
|
||||
return false;
|
||||
}
|
||||
/* Cannot perform this check without monotone clusters. */
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));
|
||||
|
||||
unsigned int num_glyphs;
|
||||
hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
|
||||
|
||||
for (unsigned int i = 1; i < num_glyphs; i++)
|
||||
if (info[i-1].cluster != info[i].cluster &&
|
||||
(info[i-1].cluster < info[i].cluster) != is_forward)
|
||||
{
|
||||
buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "clusters are not monotone.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -92,8 +93,7 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer,
|
|||
unsigned int num_features,
|
||||
const char * const *shapers)
|
||||
{
|
||||
if (buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES &&
|
||||
buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
|
||||
if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (buffer->cluster_level))
|
||||
{
|
||||
/* Cannot perform this check without monotone clusters. */
|
||||
return true;
|
||||
|
@ -207,8 +207,7 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer,
|
|||
unsigned int num_features,
|
||||
const char * const *shapers)
|
||||
{
|
||||
if (buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES &&
|
||||
buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
|
||||
if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (buffer->cluster_level))
|
||||
{
|
||||
/* Cannot perform this check without monotone clusters. */
|
||||
return true;
|
||||
|
|
|
@ -370,6 +370,18 @@ hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info)
|
|||
|
||||
len++;
|
||||
}
|
||||
void
|
||||
hb_buffer_t::add_info_and_pos (const hb_glyph_info_t &glyph_info,
|
||||
const hb_glyph_position_t &glyph_pos)
|
||||
{
|
||||
if (unlikely (!ensure (len + 1))) return;
|
||||
|
||||
info[len] = glyph_info;
|
||||
assert (have_positions);
|
||||
pos[len] = glyph_pos;
|
||||
|
||||
len++;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
|
@ -518,7 +530,7 @@ void
|
|||
hb_buffer_t::merge_clusters_impl (unsigned int start,
|
||||
unsigned int end)
|
||||
{
|
||||
if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
|
||||
if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (cluster_level))
|
||||
{
|
||||
unsafe_to_break (start, end);
|
||||
return;
|
||||
|
@ -551,7 +563,7 @@ void
|
|||
hb_buffer_t::merge_out_clusters (unsigned int start,
|
||||
unsigned int end)
|
||||
{
|
||||
if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
|
||||
if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (cluster_level))
|
||||
return;
|
||||
|
||||
if (unlikely (end - start < 2))
|
||||
|
|
|
@ -422,18 +422,34 @@ hb_buffer_get_flags (const hb_buffer_t *buffer);
|
|||
* @HB_BUFFER_CLUSTER_LEVEL_CHARACTERS: Don't group cluster values.
|
||||
* @HB_BUFFER_CLUSTER_LEVEL_DEFAULT: Default cluster level,
|
||||
* equal to @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES.
|
||||
*
|
||||
* @HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES: Only group clusters, but don't enforce monotone order.
|
||||
*
|
||||
* Data type for holding HarfBuzz's clustering behavior options. The cluster level
|
||||
* dictates one aspect of how HarfBuzz will treat non-base characters
|
||||
* dictates one aspect of how HarfBuzz will treat non-base characters
|
||||
* during shaping.
|
||||
*
|
||||
* In @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES, non-base
|
||||
* characters are merged into the cluster of the base character that precedes them.
|
||||
* There is also cluster merging every time the clusters will otherwise become non-monotone.
|
||||
*
|
||||
* In @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS, non-base characters are initially
|
||||
* assigned their own cluster values, which are not merged into preceding base
|
||||
* clusters. This allows HarfBuzz to perform additional operations like reorder
|
||||
* sequences of adjacent marks.
|
||||
* sequences of adjacent marks. The output is still monotone, but the cluster
|
||||
* values are more granular.
|
||||
*
|
||||
* In @HB_BUFFER_CLUSTER_LEVEL_CHARACTERS, non-base characters are assigned their
|
||||
* own cluster values, which are not merged into preceding base clusters. Moreover,
|
||||
* the cluster values are not merged into monotone order. This is the most granular
|
||||
* cluster level, and it is useful for clients that need to know the exact cluster
|
||||
* values of each character, but is harder to use for clients, since clusters
|
||||
* might appear in any order.
|
||||
*
|
||||
* In @HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES, non-base characters are merged into the
|
||||
* cluster of the base character that precedes them. This is similar to the Unicode
|
||||
* Grapheme Cluster algorithm, but it is not exactly the same. The output is
|
||||
* not forced to be monotone. This is useful for clients that want to use HarfBuzz
|
||||
* as a cheap implementation of the Unicode Grapheme Cluster algorithm.
|
||||
*
|
||||
* @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES is the default, because it maintains
|
||||
* backward compatibility with older versions of HarfBuzz. New client programs that
|
||||
|
@ -446,9 +462,52 @@ typedef enum {
|
|||
HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES = 0,
|
||||
HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS = 1,
|
||||
HB_BUFFER_CLUSTER_LEVEL_CHARACTERS = 2,
|
||||
HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES = 3,
|
||||
HB_BUFFER_CLUSTER_LEVEL_DEFAULT = HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES
|
||||
} hb_buffer_cluster_level_t;
|
||||
|
||||
/**
|
||||
* HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE:
|
||||
* @level: #hb_buffer_cluster_level_t to test
|
||||
*
|
||||
* Tests whether a cluster level groups cluster values into monotone order.
|
||||
* Requires that the level be valid.
|
||||
*
|
||||
* Since: 11.0.0
|
||||
*/
|
||||
#define HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE(level) \
|
||||
((bool) ((1u << (unsigned) (level)) & \
|
||||
((1u << HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES) | \
|
||||
(1u << HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS))))
|
||||
|
||||
/**
|
||||
* HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES:
|
||||
* @level: #hb_buffer_cluster_level_t to test
|
||||
*
|
||||
* Tests whether a cluster level groups cluster values by graphemes. Requires
|
||||
* that the level be valid.
|
||||
*
|
||||
* Since: 11.0.0
|
||||
*/
|
||||
#define HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES(level) \
|
||||
((bool) ((1u << (unsigned) (level)) & \
|
||||
((1u << HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES) | \
|
||||
(1u << HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES))))
|
||||
|
||||
/**
|
||||
* HB_BUFFER_CLUSTER_LEVEL_IS_CHARACTERS
|
||||
* @level: #hb_buffer_cluster_level_t to test
|
||||
*
|
||||
* Tests whether a cluster level does not group cluster values by graphemes.
|
||||
* Requires that the level be valid.
|
||||
*
|
||||
* Since: 11.0.0
|
||||
*/
|
||||
#define HB_BUFFER_CLUSTER_LEVEL_IS_CHARACTERS(level) \
|
||||
((bool) ((1u << (unsigned) (level)) & \
|
||||
((1u << HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARCATERS) | \
|
||||
(1u << HB_BUFFER_CLUSTER_LEVEL_CHARACTERS))))
|
||||
|
||||
HB_EXTERN void
|
||||
hb_buffer_set_cluster_level (hb_buffer_t *buffer,
|
||||
hb_buffer_cluster_level_t cluster_level);
|
||||
|
|
|
@ -229,6 +229,8 @@ struct hb_buffer_t
|
|||
HB_INTERNAL void add (hb_codepoint_t codepoint,
|
||||
unsigned int cluster);
|
||||
HB_INTERNAL void add_info (const hb_glyph_info_t &glyph_info);
|
||||
HB_INTERNAL void add_info_and_pos (const hb_glyph_info_t &glyph_info,
|
||||
const hb_glyph_position_t &glyph_pos);
|
||||
|
||||
void reverse_range (unsigned start, unsigned end)
|
||||
{
|
||||
|
|
|
@ -30,18 +30,31 @@
|
|||
#include "hb.hh"
|
||||
|
||||
|
||||
/* Implements a lockfree cache for int->int functions.
|
||||
/* Implements a lockfree and thread-safe cache for int->int functions,
|
||||
* using (optionally) _relaxed_ atomic integer operations.
|
||||
*
|
||||
* The cache is a fixed-size array of 16-bit or 32-bit integers.
|
||||
* The key is split into two parts: the cache index and the rest.
|
||||
* The cache is a fixed-size array of 16-bit or 32-bit integers,
|
||||
* typically 256 elements.
|
||||
*
|
||||
* The cache index is used to index into the array. The rest is used
|
||||
* to store the key and the value.
|
||||
* The key is split into two parts: the cache index (high bits)
|
||||
* and the rest (low bits).
|
||||
*
|
||||
* The cache index is used to index into the array. The array
|
||||
* member is a 16-bit or 32-bit integer that is used *both*
|
||||
* to store the low bits of the key, and the value.
|
||||
*
|
||||
* The value is stored in the least significant bits of the integer.
|
||||
* The key is stored in the most significant bits of the integer.
|
||||
* The key is shifted by cache_bits to the left to make room for the
|
||||
* value.
|
||||
* The low bits of the key are stored in the most significant bits
|
||||
* of the integer.
|
||||
*
|
||||
* A cache hit is detected by comparing the low bits of the key
|
||||
* with the high bits of the integer at the array position indexed
|
||||
* by the high bits of the key. If they match, the value is extracted
|
||||
* from the least significant bits of the integer and returned.
|
||||
* Otherwise, a cache miss is reported.
|
||||
*
|
||||
* Cache operations (storage and retrieval) involve just a few
|
||||
* arithmetic operations and a single memory access.
|
||||
*/
|
||||
|
||||
template <unsigned int key_bits=16,
|
||||
|
@ -52,11 +65,11 @@ struct hb_cache_t
|
|||
{
|
||||
using item_t = typename std::conditional<thread_safe,
|
||||
typename std::conditional<key_bits + value_bits - cache_bits <= 16,
|
||||
hb_atomic_short_t,
|
||||
hb_atomic_int_t>::type,
|
||||
hb_atomic_t<unsigned short>,
|
||||
hb_atomic_t<unsigned int>>::type,
|
||||
typename std::conditional<key_bits + value_bits - cache_bits <= 16,
|
||||
short,
|
||||
int>::type
|
||||
unsigned short,
|
||||
unsigned int>::type
|
||||
>::type;
|
||||
|
||||
static_assert ((key_bits >= cache_bits), "");
|
||||
|
|
|
@ -726,6 +726,9 @@ _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops,
|
|||
float span;
|
||||
|
||||
span = angles[n_stops - 1] - angles[0];
|
||||
if (!span)
|
||||
goto done;
|
||||
|
||||
k = 0;
|
||||
if (angles[0] >= 0)
|
||||
{
|
||||
|
|
|
@ -71,7 +71,8 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
|
|||
template <typename ACC>
|
||||
cff2_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd,
|
||||
const int *coords_=nullptr, unsigned int num_coords_=0)
|
||||
: SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs)
|
||||
: SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs),
|
||||
cached_scalars_vector (&acc.cached_scalars_vector)
|
||||
{
|
||||
coords = coords_;
|
||||
num_coords = num_coords_;
|
||||
|
@ -80,9 +81,39 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
|
|||
set_ivs (acc.privateDicts[fd].ivs);
|
||||
}
|
||||
|
||||
void fini ()
|
||||
~cff2_cs_interp_env_t ()
|
||||
{
|
||||
SUPER::fini ();
|
||||
release_scalars_vector (scalars);
|
||||
}
|
||||
|
||||
hb_vector_t<float> *acquire_scalars_vector () const
|
||||
{
|
||||
hb_vector_t<float> *scalars = cached_scalars_vector->get_acquire ();
|
||||
|
||||
if (!scalars || !cached_scalars_vector->cmpexch (scalars, nullptr))
|
||||
{
|
||||
scalars = (hb_vector_t<float> *) hb_calloc (1, sizeof (hb_vector_t<float>));
|
||||
if (unlikely (!scalars))
|
||||
return nullptr;
|
||||
scalars->init ();
|
||||
}
|
||||
|
||||
return scalars;
|
||||
}
|
||||
|
||||
void release_scalars_vector (hb_vector_t<float> *scalars) const
|
||||
{
|
||||
if (!scalars)
|
||||
return;
|
||||
|
||||
scalars->clear ();
|
||||
|
||||
if (!cached_scalars_vector->cmpexch (nullptr, scalars))
|
||||
{
|
||||
scalars->fini ();
|
||||
hb_free (scalars);
|
||||
}
|
||||
scalars = nullptr;
|
||||
}
|
||||
|
||||
op_code_t fetch_op ()
|
||||
|
@ -111,14 +142,20 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
|
|||
{
|
||||
if (!seen_blend)
|
||||
{
|
||||
region_count = varStore->varStore.get_region_index_count (get_ivs ());
|
||||
if (do_blend)
|
||||
scalars = acquire_scalars_vector ();
|
||||
if (unlikely (!scalars))
|
||||
SUPER::set_error ();
|
||||
else
|
||||
{
|
||||
if (unlikely (!scalars.resize_exact (region_count)))
|
||||
SUPER::set_error ();
|
||||
else
|
||||
varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords,
|
||||
&scalars[0], region_count);
|
||||
region_count = varStore->varStore.get_region_index_count (get_ivs ());
|
||||
if (do_blend)
|
||||
{
|
||||
if (unlikely (!scalars->resize_exact (region_count)))
|
||||
SUPER::set_error ();
|
||||
else
|
||||
varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords,
|
||||
&(*scalars)[0], region_count);
|
||||
}
|
||||
}
|
||||
seen_blend = true;
|
||||
}
|
||||
|
@ -149,11 +186,11 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
|
|||
double v = 0;
|
||||
if (do_blend)
|
||||
{
|
||||
if (likely (scalars.length == deltas.length))
|
||||
if (likely (scalars && scalars->length == deltas.length))
|
||||
{
|
||||
unsigned count = scalars.length;
|
||||
unsigned count = scalars->length;
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
v += (double) scalars.arrayZ[i] * deltas.arrayZ[i].to_real ();
|
||||
v += (double) scalars->arrayZ[i] * deltas.arrayZ[i].to_real ();
|
||||
}
|
||||
}
|
||||
return v;
|
||||
|
@ -167,7 +204,8 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
|
|||
const CFF2ItemVariationStore *varStore;
|
||||
unsigned int region_count;
|
||||
unsigned int ivs;
|
||||
hb_vector_t<float> scalars;
|
||||
hb_vector_t<float> *scalars = nullptr;
|
||||
hb_atomic_t<hb_vector_t<float> *> *cached_scalars_vector = nullptr;
|
||||
bool do_blend;
|
||||
bool seen_vsindex_ = false;
|
||||
bool seen_blend = false;
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
|
||||
/* hb_options_t */
|
||||
|
||||
hb_atomic_int_t _hb_options;
|
||||
hb_atomic_t<unsigned> _hb_options;
|
||||
|
||||
void
|
||||
_hb_options_init ()
|
||||
|
@ -273,7 +273,7 @@ struct hb_language_item_t {
|
|||
|
||||
/* Thread-safe lockfree language list */
|
||||
|
||||
static hb_atomic_ptr_t <hb_language_item_t> langs;
|
||||
static hb_atomic_t<hb_language_item_t *> langs;
|
||||
|
||||
static inline void
|
||||
free_langs ()
|
||||
|
@ -403,7 +403,7 @@ hb_language_to_string (hb_language_t language)
|
|||
hb_language_t
|
||||
hb_language_get_default ()
|
||||
{
|
||||
static hb_atomic_ptr_t <hb_language_t> default_language;
|
||||
static hb_atomic_t<hb_language_t> default_language;
|
||||
|
||||
hb_language_t language = default_language;
|
||||
if (unlikely (language == HB_LANGUAGE_INVALID))
|
||||
|
@ -968,6 +968,9 @@ hb_feature_from_string (const char *str, int len,
|
|||
* understood by hb_feature_from_string(). The client in responsible for
|
||||
* allocating big enough size for @buf, 128 bytes is more than enough.
|
||||
*
|
||||
* Note that the feature value will be omitted if it is '1', but the
|
||||
* string won't include any whitespace.
|
||||
*
|
||||
* Since: 0.9.5
|
||||
**/
|
||||
void
|
||||
|
@ -1121,6 +1124,8 @@ get_C_locale ()
|
|||
* understood by hb_variation_from_string(). The client in responsible for
|
||||
* allocating big enough size for @buf, 128 bytes is more than enough.
|
||||
*
|
||||
* Note that the string won't include any whitespace.
|
||||
*
|
||||
* Since: 1.4.2
|
||||
*/
|
||||
void
|
||||
|
@ -1212,6 +1217,58 @@ uint8_t
|
|||
return hb_color_get_blue (color);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_malloc:
|
||||
* @size: The size of the memory to allocate.
|
||||
*
|
||||
* Allocates @size bytes of memory, using the allocator set at
|
||||
* compile-time. Typically just malloc().
|
||||
*
|
||||
* Return value: A pointer to the allocated memory.
|
||||
*
|
||||
* Since: 11.0.0
|
||||
**/
|
||||
void* hb_malloc(size_t size) { return hb_malloc_impl (size); }
|
||||
|
||||
/**
|
||||
* hb_calloc:
|
||||
* @nmemb: The number of elements to allocate.
|
||||
* @size: The size of each element.
|
||||
*
|
||||
* Allocates @nmemb elements of @size bytes each, initialized to zero,
|
||||
* using the allocator set at compile-time. Typically just calloc().
|
||||
*
|
||||
* Return value: A pointer to the allocated memory.
|
||||
*
|
||||
* Since: 11.0.0
|
||||
**/
|
||||
void* hb_calloc(size_t nmemb, size_t size) { return hb_calloc_impl (nmemb, size); }
|
||||
|
||||
/**
|
||||
* hb_realloc:
|
||||
* @ptr: The pointer to the memory to reallocate.
|
||||
* @size: The new size of the memory.
|
||||
*
|
||||
* Reallocates the memory pointed to by @ptr to @size bytes, using the
|
||||
* allocator set at compile-time. Typically just realloc().
|
||||
*
|
||||
* Return value: A pointer to the reallocated memory.
|
||||
*
|
||||
* Since: 11.0.0
|
||||
**/
|
||||
void* hb_realloc(void *ptr, size_t size) { return hb_realloc_impl (ptr, size); }
|
||||
|
||||
/**
|
||||
* hb_free:
|
||||
* @ptr: The pointer to the memory to free.
|
||||
*
|
||||
* Frees the memory pointed to by @ptr, using the allocator set at
|
||||
* compile-time. Typically just free().
|
||||
*
|
||||
* Since: 11.0.0
|
||||
**/
|
||||
void hb_free(void *ptr) { hb_free_impl (ptr); }
|
||||
|
||||
|
||||
/* If there is no visibility control, then hb-static.cc will NOT
|
||||
* define anything. Instead, we get it to define one set in here
|
||||
|
|
443
src/hb-common.h
443
src/hb-common.h
|
@ -65,6 +65,7 @@ typedef unsigned __int64 uint64_t;
|
|||
#else
|
||||
# include <inttypes.h>
|
||||
#endif
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
|
||||
#define HB_DEPRECATED __attribute__((__deprecated__))
|
||||
|
@ -337,437 +338,7 @@ HB_EXTERN hb_bool_t
|
|||
hb_language_matches (hb_language_t language,
|
||||
hb_language_t specific);
|
||||
|
||||
/**
|
||||
* hb_script_t:
|
||||
* @HB_SCRIPT_COMMON: `Zyyy`
|
||||
* @HB_SCRIPT_INHERITED: `Zinh`
|
||||
* @HB_SCRIPT_UNKNOWN: `Zzzz`
|
||||
* @HB_SCRIPT_ARABIC: `Arab`
|
||||
* @HB_SCRIPT_ARMENIAN: `Armn`
|
||||
* @HB_SCRIPT_BENGALI: `Beng`
|
||||
* @HB_SCRIPT_CYRILLIC: `Cyrl`
|
||||
* @HB_SCRIPT_DEVANAGARI: `Deva`
|
||||
* @HB_SCRIPT_GEORGIAN: `Geor`
|
||||
* @HB_SCRIPT_GREEK: `Grek`
|
||||
* @HB_SCRIPT_GUJARATI: `Gujr`
|
||||
* @HB_SCRIPT_GURMUKHI: `Guru`
|
||||
* @HB_SCRIPT_HANGUL: `Hang`
|
||||
* @HB_SCRIPT_HAN: `Hani`
|
||||
* @HB_SCRIPT_HEBREW: `Hebr`
|
||||
* @HB_SCRIPT_HIRAGANA: `Hira`
|
||||
* @HB_SCRIPT_KANNADA: `Knda`
|
||||
* @HB_SCRIPT_KATAKANA: `Kana`
|
||||
* @HB_SCRIPT_LAO: `Laoo`
|
||||
* @HB_SCRIPT_LATIN: `Latn`
|
||||
* @HB_SCRIPT_MALAYALAM: `Mlym`
|
||||
* @HB_SCRIPT_ORIYA: `Orya`
|
||||
* @HB_SCRIPT_TAMIL: `Taml`
|
||||
* @HB_SCRIPT_TELUGU: `Telu`
|
||||
* @HB_SCRIPT_THAI: `Thai`
|
||||
* @HB_SCRIPT_TIBETAN: `Tibt`
|
||||
* @HB_SCRIPT_BOPOMOFO: `Bopo`
|
||||
* @HB_SCRIPT_BRAILLE: `Brai`
|
||||
* @HB_SCRIPT_CANADIAN_SYLLABICS: `Cans`
|
||||
* @HB_SCRIPT_CHEROKEE: `Cher`
|
||||
* @HB_SCRIPT_ETHIOPIC: `Ethi`
|
||||
* @HB_SCRIPT_KHMER: `Khmr`
|
||||
* @HB_SCRIPT_MONGOLIAN: `Mong`
|
||||
* @HB_SCRIPT_MYANMAR: `Mymr`
|
||||
* @HB_SCRIPT_OGHAM: `Ogam`
|
||||
* @HB_SCRIPT_RUNIC: `Runr`
|
||||
* @HB_SCRIPT_SINHALA: `Sinh`
|
||||
* @HB_SCRIPT_SYRIAC: `Syrc`
|
||||
* @HB_SCRIPT_THAANA: `Thaa`
|
||||
* @HB_SCRIPT_YI: `Yiii`
|
||||
* @HB_SCRIPT_DESERET: `Dsrt`
|
||||
* @HB_SCRIPT_GOTHIC: `Goth`
|
||||
* @HB_SCRIPT_OLD_ITALIC: `Ital`
|
||||
* @HB_SCRIPT_BUHID: `Buhd`
|
||||
* @HB_SCRIPT_HANUNOO: `Hano`
|
||||
* @HB_SCRIPT_TAGALOG: `Tglg`
|
||||
* @HB_SCRIPT_TAGBANWA: `Tagb`
|
||||
* @HB_SCRIPT_CYPRIOT: `Cprt`
|
||||
* @HB_SCRIPT_LIMBU: `Limb`
|
||||
* @HB_SCRIPT_LINEAR_B: `Linb`
|
||||
* @HB_SCRIPT_OSMANYA: `Osma`
|
||||
* @HB_SCRIPT_SHAVIAN: `Shaw`
|
||||
* @HB_SCRIPT_TAI_LE: `Tale`
|
||||
* @HB_SCRIPT_UGARITIC: `Ugar`
|
||||
* @HB_SCRIPT_BUGINESE: `Bugi`
|
||||
* @HB_SCRIPT_COPTIC: `Copt`
|
||||
* @HB_SCRIPT_GLAGOLITIC: `Glag`
|
||||
* @HB_SCRIPT_KHAROSHTHI: `Khar`
|
||||
* @HB_SCRIPT_NEW_TAI_LUE: `Talu`
|
||||
* @HB_SCRIPT_OLD_PERSIAN: `Xpeo`
|
||||
* @HB_SCRIPT_SYLOTI_NAGRI: `Sylo`
|
||||
* @HB_SCRIPT_TIFINAGH: `Tfng`
|
||||
* @HB_SCRIPT_BALINESE: `Bali`
|
||||
* @HB_SCRIPT_CUNEIFORM: `Xsux`
|
||||
* @HB_SCRIPT_NKO: `Nkoo`
|
||||
* @HB_SCRIPT_PHAGS_PA: `Phag`
|
||||
* @HB_SCRIPT_PHOENICIAN: `Phnx`
|
||||
* @HB_SCRIPT_CARIAN: `Cari`
|
||||
* @HB_SCRIPT_CHAM: `Cham`
|
||||
* @HB_SCRIPT_KAYAH_LI: `Kali`
|
||||
* @HB_SCRIPT_LEPCHA: `Lepc`
|
||||
* @HB_SCRIPT_LYCIAN: `Lyci`
|
||||
* @HB_SCRIPT_LYDIAN: `Lydi`
|
||||
* @HB_SCRIPT_OL_CHIKI: `Olck`
|
||||
* @HB_SCRIPT_REJANG: `Rjng`
|
||||
* @HB_SCRIPT_SAURASHTRA: `Saur`
|
||||
* @HB_SCRIPT_SUNDANESE: `Sund`
|
||||
* @HB_SCRIPT_VAI: `Vaii`
|
||||
* @HB_SCRIPT_AVESTAN: `Avst`
|
||||
* @HB_SCRIPT_BAMUM: `Bamu`
|
||||
* @HB_SCRIPT_EGYPTIAN_HIEROGLYPHS: `Egyp`
|
||||
* @HB_SCRIPT_IMPERIAL_ARAMAIC: `Armi`
|
||||
* @HB_SCRIPT_INSCRIPTIONAL_PAHLAVI: `Phli`
|
||||
* @HB_SCRIPT_INSCRIPTIONAL_PARTHIAN: `Prti`
|
||||
* @HB_SCRIPT_JAVANESE: `Java`
|
||||
* @HB_SCRIPT_KAITHI: `Kthi`
|
||||
* @HB_SCRIPT_LISU: `Lisu`
|
||||
* @HB_SCRIPT_MEETEI_MAYEK: `Mtei`
|
||||
* @HB_SCRIPT_OLD_SOUTH_ARABIAN: `Sarb`
|
||||
* @HB_SCRIPT_OLD_TURKIC: `Orkh`
|
||||
* @HB_SCRIPT_SAMARITAN: `Samr`
|
||||
* @HB_SCRIPT_TAI_THAM: `Lana`
|
||||
* @HB_SCRIPT_TAI_VIET: `Tavt`
|
||||
* @HB_SCRIPT_BATAK: `Batk`
|
||||
* @HB_SCRIPT_BRAHMI: `Brah`
|
||||
* @HB_SCRIPT_MANDAIC: `Mand`
|
||||
* @HB_SCRIPT_CHAKMA: `Cakm`
|
||||
* @HB_SCRIPT_MEROITIC_CURSIVE: `Merc`
|
||||
* @HB_SCRIPT_MEROITIC_HIEROGLYPHS: `Mero`
|
||||
* @HB_SCRIPT_MIAO: `Plrd`
|
||||
* @HB_SCRIPT_SHARADA: `Shrd`
|
||||
* @HB_SCRIPT_SORA_SOMPENG: `Sora`
|
||||
* @HB_SCRIPT_TAKRI: `Takr`
|
||||
* @HB_SCRIPT_BASSA_VAH: `Bass`, Since: 0.9.30
|
||||
* @HB_SCRIPT_CAUCASIAN_ALBANIAN: `Aghb`, Since: 0.9.30
|
||||
* @HB_SCRIPT_DUPLOYAN: `Dupl`, Since: 0.9.30
|
||||
* @HB_SCRIPT_ELBASAN: `Elba`, Since: 0.9.30
|
||||
* @HB_SCRIPT_GRANTHA: `Gran`, Since: 0.9.30
|
||||
* @HB_SCRIPT_KHOJKI: `Khoj`, Since: 0.9.30
|
||||
* @HB_SCRIPT_KHUDAWADI: `Sind`, Since: 0.9.30
|
||||
* @HB_SCRIPT_LINEAR_A: `Lina`, Since: 0.9.30
|
||||
* @HB_SCRIPT_MAHAJANI: `Mahj`, Since: 0.9.30
|
||||
* @HB_SCRIPT_MANICHAEAN: `Mani`, Since: 0.9.30
|
||||
* @HB_SCRIPT_MENDE_KIKAKUI: `Mend`, Since: 0.9.30
|
||||
* @HB_SCRIPT_MODI: `Modi`, Since: 0.9.30
|
||||
* @HB_SCRIPT_MRO: `Mroo`, Since: 0.9.30
|
||||
* @HB_SCRIPT_NABATAEAN: `Nbat`, Since: 0.9.30
|
||||
* @HB_SCRIPT_OLD_NORTH_ARABIAN: `Narb`, Since: 0.9.30
|
||||
* @HB_SCRIPT_OLD_PERMIC: `Perm`, Since: 0.9.30
|
||||
* @HB_SCRIPT_PAHAWH_HMONG: `Hmng`, Since: 0.9.30
|
||||
* @HB_SCRIPT_PALMYRENE: `Palm`, Since: 0.9.30
|
||||
* @HB_SCRIPT_PAU_CIN_HAU: `Pauc`, Since: 0.9.30
|
||||
* @HB_SCRIPT_PSALTER_PAHLAVI: `Phlp`, Since: 0.9.30
|
||||
* @HB_SCRIPT_SIDDHAM: `Sidd`, Since: 0.9.30
|
||||
* @HB_SCRIPT_TIRHUTA: `Tirh`, Since: 0.9.30
|
||||
* @HB_SCRIPT_WARANG_CITI: `Wara`, Since: 0.9.30
|
||||
* @HB_SCRIPT_AHOM: `Ahom`, Since: 0.9.30
|
||||
* @HB_SCRIPT_ANATOLIAN_HIEROGLYPHS: `Hluw`, Since: 0.9.30
|
||||
* @HB_SCRIPT_HATRAN: `Hatr`, Since: 0.9.30
|
||||
* @HB_SCRIPT_MULTANI: `Mult`, Since: 0.9.30
|
||||
* @HB_SCRIPT_OLD_HUNGARIAN: `Hung`, Since: 0.9.30
|
||||
* @HB_SCRIPT_SIGNWRITING: `Sgnw`, Since: 0.9.30
|
||||
* @HB_SCRIPT_ADLAM: `Adlm`, Since: 1.3.0
|
||||
* @HB_SCRIPT_BHAIKSUKI: `Bhks`, Since: 1.3.0
|
||||
* @HB_SCRIPT_MARCHEN: `Marc`, Since: 1.3.0
|
||||
* @HB_SCRIPT_OSAGE: `Osge`, Since: 1.3.0
|
||||
* @HB_SCRIPT_TANGUT: `Tang`, Since: 1.3.0
|
||||
* @HB_SCRIPT_NEWA: `Newa`, Since: 1.3.0
|
||||
* @HB_SCRIPT_MASARAM_GONDI: `Gonm`, Since: 1.6.0
|
||||
* @HB_SCRIPT_NUSHU: `Nshu`, Since: 1.6.0
|
||||
* @HB_SCRIPT_SOYOMBO: `Soyo`, Since: 1.6.0
|
||||
* @HB_SCRIPT_ZANABAZAR_SQUARE: `Zanb`, Since: 1.6.0
|
||||
* @HB_SCRIPT_DOGRA: `Dogr`, Since: 1.8.0
|
||||
* @HB_SCRIPT_GUNJALA_GONDI: `Gong`, Since: 1.8.0
|
||||
* @HB_SCRIPT_HANIFI_ROHINGYA: `Rohg`, Since: 1.8.0
|
||||
* @HB_SCRIPT_MAKASAR: `Maka`, Since: 1.8.0
|
||||
* @HB_SCRIPT_MEDEFAIDRIN: `Medf`, Since: 1.8.0
|
||||
* @HB_SCRIPT_OLD_SOGDIAN: `Sogo`, Since: 1.8.0
|
||||
* @HB_SCRIPT_SOGDIAN: `Sogd`, Since: 1.8.0
|
||||
* @HB_SCRIPT_ELYMAIC: `Elym`, Since: 2.4.0
|
||||
* @HB_SCRIPT_NANDINAGARI: `Nand`, Since: 2.4.0
|
||||
* @HB_SCRIPT_NYIAKENG_PUACHUE_HMONG: `Hmnp`, Since: 2.4.0
|
||||
* @HB_SCRIPT_WANCHO: `Wcho`, Since: 2.4.0
|
||||
* @HB_SCRIPT_CHORASMIAN: `Chrs`, Since: 2.6.7
|
||||
* @HB_SCRIPT_DIVES_AKURU: `Diak`, Since: 2.6.7
|
||||
* @HB_SCRIPT_KHITAN_SMALL_SCRIPT: `Kits`, Since: 2.6.7
|
||||
* @HB_SCRIPT_YEZIDI: `Yezi`, Since: 2.6.7
|
||||
* @HB_SCRIPT_CYPRO_MINOAN: `Cpmn`, Since: 3.0.0
|
||||
* @HB_SCRIPT_OLD_UYGHUR: `Ougr`, Since: 3.0.0
|
||||
* @HB_SCRIPT_TANGSA: `Tnsa`, Since: 3.0.0
|
||||
* @HB_SCRIPT_TOTO: `Toto`, Since: 3.0.0
|
||||
* @HB_SCRIPT_VITHKUQI: `Vith`, Since: 3.0.0
|
||||
* @HB_SCRIPT_MATH: `Zmth`, Since: 3.4.0
|
||||
* @HB_SCRIPT_KAWI: `Kawi`, Since: 5.2.0
|
||||
* @HB_SCRIPT_NAG_MUNDARI: `Nagm`, Since: 5.2.0
|
||||
* @HB_SCRIPT_GARAY: `Gara`, Since: 10.0.0
|
||||
* @HB_SCRIPT_GURUNG_KHEMA: `Gukh`, Since: 10.0.0
|
||||
* @HB_SCRIPT_KIRAT_RAI: `Krai`, Since: 10.0.0
|
||||
* @HB_SCRIPT_OL_ONAL: `Onao`, Since: 10.0.0
|
||||
* @HB_SCRIPT_SUNUWAR: `Sunu`, Since: 10.0.0
|
||||
* @HB_SCRIPT_TODHRI: `Todr`, Since: 10.0.0
|
||||
* @HB_SCRIPT_TULU_TIGALARI: `Tutg`, Since: 10.0.0
|
||||
* @HB_SCRIPT_INVALID: No script set
|
||||
*
|
||||
* Data type for scripts. Each #hb_script_t's value is an #hb_tag_t corresponding
|
||||
* to the four-letter values defined by [ISO 15924](https://unicode.org/iso15924/).
|
||||
*
|
||||
* See also the Script (sc) property of the Unicode Character Database.
|
||||
*
|
||||
**/
|
||||
|
||||
/* https://docs.google.com/spreadsheets/d/1Y90M0Ie3MUJ6UVCRDOypOtijlMDLNNyyLk36T6iMu0o */
|
||||
typedef enum
|
||||
{
|
||||
HB_SCRIPT_COMMON = HB_TAG ('Z','y','y','y'), /*1.1*/
|
||||
HB_SCRIPT_INHERITED = HB_TAG ('Z','i','n','h'), /*1.1*/
|
||||
HB_SCRIPT_UNKNOWN = HB_TAG ('Z','z','z','z'), /*5.0*/
|
||||
|
||||
HB_SCRIPT_ARABIC = HB_TAG ('A','r','a','b'), /*1.1*/
|
||||
HB_SCRIPT_ARMENIAN = HB_TAG ('A','r','m','n'), /*1.1*/
|
||||
HB_SCRIPT_BENGALI = HB_TAG ('B','e','n','g'), /*1.1*/
|
||||
HB_SCRIPT_CYRILLIC = HB_TAG ('C','y','r','l'), /*1.1*/
|
||||
HB_SCRIPT_DEVANAGARI = HB_TAG ('D','e','v','a'), /*1.1*/
|
||||
HB_SCRIPT_GEORGIAN = HB_TAG ('G','e','o','r'), /*1.1*/
|
||||
HB_SCRIPT_GREEK = HB_TAG ('G','r','e','k'), /*1.1*/
|
||||
HB_SCRIPT_GUJARATI = HB_TAG ('G','u','j','r'), /*1.1*/
|
||||
HB_SCRIPT_GURMUKHI = HB_TAG ('G','u','r','u'), /*1.1*/
|
||||
HB_SCRIPT_HANGUL = HB_TAG ('H','a','n','g'), /*1.1*/
|
||||
HB_SCRIPT_HAN = HB_TAG ('H','a','n','i'), /*1.1*/
|
||||
HB_SCRIPT_HEBREW = HB_TAG ('H','e','b','r'), /*1.1*/
|
||||
HB_SCRIPT_HIRAGANA = HB_TAG ('H','i','r','a'), /*1.1*/
|
||||
HB_SCRIPT_KANNADA = HB_TAG ('K','n','d','a'), /*1.1*/
|
||||
HB_SCRIPT_KATAKANA = HB_TAG ('K','a','n','a'), /*1.1*/
|
||||
HB_SCRIPT_LAO = HB_TAG ('L','a','o','o'), /*1.1*/
|
||||
HB_SCRIPT_LATIN = HB_TAG ('L','a','t','n'), /*1.1*/
|
||||
HB_SCRIPT_MALAYALAM = HB_TAG ('M','l','y','m'), /*1.1*/
|
||||
HB_SCRIPT_ORIYA = HB_TAG ('O','r','y','a'), /*1.1*/
|
||||
HB_SCRIPT_TAMIL = HB_TAG ('T','a','m','l'), /*1.1*/
|
||||
HB_SCRIPT_TELUGU = HB_TAG ('T','e','l','u'), /*1.1*/
|
||||
HB_SCRIPT_THAI = HB_TAG ('T','h','a','i'), /*1.1*/
|
||||
|
||||
HB_SCRIPT_TIBETAN = HB_TAG ('T','i','b','t'), /*2.0*/
|
||||
|
||||
HB_SCRIPT_BOPOMOFO = HB_TAG ('B','o','p','o'), /*3.0*/
|
||||
HB_SCRIPT_BRAILLE = HB_TAG ('B','r','a','i'), /*3.0*/
|
||||
HB_SCRIPT_CANADIAN_SYLLABICS = HB_TAG ('C','a','n','s'), /*3.0*/
|
||||
HB_SCRIPT_CHEROKEE = HB_TAG ('C','h','e','r'), /*3.0*/
|
||||
HB_SCRIPT_ETHIOPIC = HB_TAG ('E','t','h','i'), /*3.0*/
|
||||
HB_SCRIPT_KHMER = HB_TAG ('K','h','m','r'), /*3.0*/
|
||||
HB_SCRIPT_MONGOLIAN = HB_TAG ('M','o','n','g'), /*3.0*/
|
||||
HB_SCRIPT_MYANMAR = HB_TAG ('M','y','m','r'), /*3.0*/
|
||||
HB_SCRIPT_OGHAM = HB_TAG ('O','g','a','m'), /*3.0*/
|
||||
HB_SCRIPT_RUNIC = HB_TAG ('R','u','n','r'), /*3.0*/
|
||||
HB_SCRIPT_SINHALA = HB_TAG ('S','i','n','h'), /*3.0*/
|
||||
HB_SCRIPT_SYRIAC = HB_TAG ('S','y','r','c'), /*3.0*/
|
||||
HB_SCRIPT_THAANA = HB_TAG ('T','h','a','a'), /*3.0*/
|
||||
HB_SCRIPT_YI = HB_TAG ('Y','i','i','i'), /*3.0*/
|
||||
|
||||
HB_SCRIPT_DESERET = HB_TAG ('D','s','r','t'), /*3.1*/
|
||||
HB_SCRIPT_GOTHIC = HB_TAG ('G','o','t','h'), /*3.1*/
|
||||
HB_SCRIPT_OLD_ITALIC = HB_TAG ('I','t','a','l'), /*3.1*/
|
||||
|
||||
HB_SCRIPT_BUHID = HB_TAG ('B','u','h','d'), /*3.2*/
|
||||
HB_SCRIPT_HANUNOO = HB_TAG ('H','a','n','o'), /*3.2*/
|
||||
HB_SCRIPT_TAGALOG = HB_TAG ('T','g','l','g'), /*3.2*/
|
||||
HB_SCRIPT_TAGBANWA = HB_TAG ('T','a','g','b'), /*3.2*/
|
||||
|
||||
HB_SCRIPT_CYPRIOT = HB_TAG ('C','p','r','t'), /*4.0*/
|
||||
HB_SCRIPT_LIMBU = HB_TAG ('L','i','m','b'), /*4.0*/
|
||||
HB_SCRIPT_LINEAR_B = HB_TAG ('L','i','n','b'), /*4.0*/
|
||||
HB_SCRIPT_OSMANYA = HB_TAG ('O','s','m','a'), /*4.0*/
|
||||
HB_SCRIPT_SHAVIAN = HB_TAG ('S','h','a','w'), /*4.0*/
|
||||
HB_SCRIPT_TAI_LE = HB_TAG ('T','a','l','e'), /*4.0*/
|
||||
HB_SCRIPT_UGARITIC = HB_TAG ('U','g','a','r'), /*4.0*/
|
||||
|
||||
HB_SCRIPT_BUGINESE = HB_TAG ('B','u','g','i'), /*4.1*/
|
||||
HB_SCRIPT_COPTIC = HB_TAG ('C','o','p','t'), /*4.1*/
|
||||
HB_SCRIPT_GLAGOLITIC = HB_TAG ('G','l','a','g'), /*4.1*/
|
||||
HB_SCRIPT_KHAROSHTHI = HB_TAG ('K','h','a','r'), /*4.1*/
|
||||
HB_SCRIPT_NEW_TAI_LUE = HB_TAG ('T','a','l','u'), /*4.1*/
|
||||
HB_SCRIPT_OLD_PERSIAN = HB_TAG ('X','p','e','o'), /*4.1*/
|
||||
HB_SCRIPT_SYLOTI_NAGRI = HB_TAG ('S','y','l','o'), /*4.1*/
|
||||
HB_SCRIPT_TIFINAGH = HB_TAG ('T','f','n','g'), /*4.1*/
|
||||
|
||||
HB_SCRIPT_BALINESE = HB_TAG ('B','a','l','i'), /*5.0*/
|
||||
HB_SCRIPT_CUNEIFORM = HB_TAG ('X','s','u','x'), /*5.0*/
|
||||
HB_SCRIPT_NKO = HB_TAG ('N','k','o','o'), /*5.0*/
|
||||
HB_SCRIPT_PHAGS_PA = HB_TAG ('P','h','a','g'), /*5.0*/
|
||||
HB_SCRIPT_PHOENICIAN = HB_TAG ('P','h','n','x'), /*5.0*/
|
||||
|
||||
HB_SCRIPT_CARIAN = HB_TAG ('C','a','r','i'), /*5.1*/
|
||||
HB_SCRIPT_CHAM = HB_TAG ('C','h','a','m'), /*5.1*/
|
||||
HB_SCRIPT_KAYAH_LI = HB_TAG ('K','a','l','i'), /*5.1*/
|
||||
HB_SCRIPT_LEPCHA = HB_TAG ('L','e','p','c'), /*5.1*/
|
||||
HB_SCRIPT_LYCIAN = HB_TAG ('L','y','c','i'), /*5.1*/
|
||||
HB_SCRIPT_LYDIAN = HB_TAG ('L','y','d','i'), /*5.1*/
|
||||
HB_SCRIPT_OL_CHIKI = HB_TAG ('O','l','c','k'), /*5.1*/
|
||||
HB_SCRIPT_REJANG = HB_TAG ('R','j','n','g'), /*5.1*/
|
||||
HB_SCRIPT_SAURASHTRA = HB_TAG ('S','a','u','r'), /*5.1*/
|
||||
HB_SCRIPT_SUNDANESE = HB_TAG ('S','u','n','d'), /*5.1*/
|
||||
HB_SCRIPT_VAI = HB_TAG ('V','a','i','i'), /*5.1*/
|
||||
|
||||
HB_SCRIPT_AVESTAN = HB_TAG ('A','v','s','t'), /*5.2*/
|
||||
HB_SCRIPT_BAMUM = HB_TAG ('B','a','m','u'), /*5.2*/
|
||||
HB_SCRIPT_EGYPTIAN_HIEROGLYPHS = HB_TAG ('E','g','y','p'), /*5.2*/
|
||||
HB_SCRIPT_IMPERIAL_ARAMAIC = HB_TAG ('A','r','m','i'), /*5.2*/
|
||||
HB_SCRIPT_INSCRIPTIONAL_PAHLAVI = HB_TAG ('P','h','l','i'), /*5.2*/
|
||||
HB_SCRIPT_INSCRIPTIONAL_PARTHIAN = HB_TAG ('P','r','t','i'), /*5.2*/
|
||||
HB_SCRIPT_JAVANESE = HB_TAG ('J','a','v','a'), /*5.2*/
|
||||
HB_SCRIPT_KAITHI = HB_TAG ('K','t','h','i'), /*5.2*/
|
||||
HB_SCRIPT_LISU = HB_TAG ('L','i','s','u'), /*5.2*/
|
||||
HB_SCRIPT_MEETEI_MAYEK = HB_TAG ('M','t','e','i'), /*5.2*/
|
||||
HB_SCRIPT_OLD_SOUTH_ARABIAN = HB_TAG ('S','a','r','b'), /*5.2*/
|
||||
HB_SCRIPT_OLD_TURKIC = HB_TAG ('O','r','k','h'), /*5.2*/
|
||||
HB_SCRIPT_SAMARITAN = HB_TAG ('S','a','m','r'), /*5.2*/
|
||||
HB_SCRIPT_TAI_THAM = HB_TAG ('L','a','n','a'), /*5.2*/
|
||||
HB_SCRIPT_TAI_VIET = HB_TAG ('T','a','v','t'), /*5.2*/
|
||||
|
||||
HB_SCRIPT_BATAK = HB_TAG ('B','a','t','k'), /*6.0*/
|
||||
HB_SCRIPT_BRAHMI = HB_TAG ('B','r','a','h'), /*6.0*/
|
||||
HB_SCRIPT_MANDAIC = HB_TAG ('M','a','n','d'), /*6.0*/
|
||||
|
||||
HB_SCRIPT_CHAKMA = HB_TAG ('C','a','k','m'), /*6.1*/
|
||||
HB_SCRIPT_MEROITIC_CURSIVE = HB_TAG ('M','e','r','c'), /*6.1*/
|
||||
HB_SCRIPT_MEROITIC_HIEROGLYPHS = HB_TAG ('M','e','r','o'), /*6.1*/
|
||||
HB_SCRIPT_MIAO = HB_TAG ('P','l','r','d'), /*6.1*/
|
||||
HB_SCRIPT_SHARADA = HB_TAG ('S','h','r','d'), /*6.1*/
|
||||
HB_SCRIPT_SORA_SOMPENG = HB_TAG ('S','o','r','a'), /*6.1*/
|
||||
HB_SCRIPT_TAKRI = HB_TAG ('T','a','k','r'), /*6.1*/
|
||||
|
||||
/*
|
||||
* Since: 0.9.30
|
||||
*/
|
||||
HB_SCRIPT_BASSA_VAH = HB_TAG ('B','a','s','s'), /*7.0*/
|
||||
HB_SCRIPT_CAUCASIAN_ALBANIAN = HB_TAG ('A','g','h','b'), /*7.0*/
|
||||
HB_SCRIPT_DUPLOYAN = HB_TAG ('D','u','p','l'), /*7.0*/
|
||||
HB_SCRIPT_ELBASAN = HB_TAG ('E','l','b','a'), /*7.0*/
|
||||
HB_SCRIPT_GRANTHA = HB_TAG ('G','r','a','n'), /*7.0*/
|
||||
HB_SCRIPT_KHOJKI = HB_TAG ('K','h','o','j'), /*7.0*/
|
||||
HB_SCRIPT_KHUDAWADI = HB_TAG ('S','i','n','d'), /*7.0*/
|
||||
HB_SCRIPT_LINEAR_A = HB_TAG ('L','i','n','a'), /*7.0*/
|
||||
HB_SCRIPT_MAHAJANI = HB_TAG ('M','a','h','j'), /*7.0*/
|
||||
HB_SCRIPT_MANICHAEAN = HB_TAG ('M','a','n','i'), /*7.0*/
|
||||
HB_SCRIPT_MENDE_KIKAKUI = HB_TAG ('M','e','n','d'), /*7.0*/
|
||||
HB_SCRIPT_MODI = HB_TAG ('M','o','d','i'), /*7.0*/
|
||||
HB_SCRIPT_MRO = HB_TAG ('M','r','o','o'), /*7.0*/
|
||||
HB_SCRIPT_NABATAEAN = HB_TAG ('N','b','a','t'), /*7.0*/
|
||||
HB_SCRIPT_OLD_NORTH_ARABIAN = HB_TAG ('N','a','r','b'), /*7.0*/
|
||||
HB_SCRIPT_OLD_PERMIC = HB_TAG ('P','e','r','m'), /*7.0*/
|
||||
HB_SCRIPT_PAHAWH_HMONG = HB_TAG ('H','m','n','g'), /*7.0*/
|
||||
HB_SCRIPT_PALMYRENE = HB_TAG ('P','a','l','m'), /*7.0*/
|
||||
HB_SCRIPT_PAU_CIN_HAU = HB_TAG ('P','a','u','c'), /*7.0*/
|
||||
HB_SCRIPT_PSALTER_PAHLAVI = HB_TAG ('P','h','l','p'), /*7.0*/
|
||||
HB_SCRIPT_SIDDHAM = HB_TAG ('S','i','d','d'), /*7.0*/
|
||||
HB_SCRIPT_TIRHUTA = HB_TAG ('T','i','r','h'), /*7.0*/
|
||||
HB_SCRIPT_WARANG_CITI = HB_TAG ('W','a','r','a'), /*7.0*/
|
||||
|
||||
HB_SCRIPT_AHOM = HB_TAG ('A','h','o','m'), /*8.0*/
|
||||
HB_SCRIPT_ANATOLIAN_HIEROGLYPHS = HB_TAG ('H','l','u','w'), /*8.0*/
|
||||
HB_SCRIPT_HATRAN = HB_TAG ('H','a','t','r'), /*8.0*/
|
||||
HB_SCRIPT_MULTANI = HB_TAG ('M','u','l','t'), /*8.0*/
|
||||
HB_SCRIPT_OLD_HUNGARIAN = HB_TAG ('H','u','n','g'), /*8.0*/
|
||||
HB_SCRIPT_SIGNWRITING = HB_TAG ('S','g','n','w'), /*8.0*/
|
||||
|
||||
/*
|
||||
* Since 1.3.0
|
||||
*/
|
||||
HB_SCRIPT_ADLAM = HB_TAG ('A','d','l','m'), /*9.0*/
|
||||
HB_SCRIPT_BHAIKSUKI = HB_TAG ('B','h','k','s'), /*9.0*/
|
||||
HB_SCRIPT_MARCHEN = HB_TAG ('M','a','r','c'), /*9.0*/
|
||||
HB_SCRIPT_OSAGE = HB_TAG ('O','s','g','e'), /*9.0*/
|
||||
HB_SCRIPT_TANGUT = HB_TAG ('T','a','n','g'), /*9.0*/
|
||||
HB_SCRIPT_NEWA = HB_TAG ('N','e','w','a'), /*9.0*/
|
||||
|
||||
/*
|
||||
* Since 1.6.0
|
||||
*/
|
||||
HB_SCRIPT_MASARAM_GONDI = HB_TAG ('G','o','n','m'), /*10.0*/
|
||||
HB_SCRIPT_NUSHU = HB_TAG ('N','s','h','u'), /*10.0*/
|
||||
HB_SCRIPT_SOYOMBO = HB_TAG ('S','o','y','o'), /*10.0*/
|
||||
HB_SCRIPT_ZANABAZAR_SQUARE = HB_TAG ('Z','a','n','b'), /*10.0*/
|
||||
|
||||
/*
|
||||
* Since 1.8.0
|
||||
*/
|
||||
HB_SCRIPT_DOGRA = HB_TAG ('D','o','g','r'), /*11.0*/
|
||||
HB_SCRIPT_GUNJALA_GONDI = HB_TAG ('G','o','n','g'), /*11.0*/
|
||||
HB_SCRIPT_HANIFI_ROHINGYA = HB_TAG ('R','o','h','g'), /*11.0*/
|
||||
HB_SCRIPT_MAKASAR = HB_TAG ('M','a','k','a'), /*11.0*/
|
||||
HB_SCRIPT_MEDEFAIDRIN = HB_TAG ('M','e','d','f'), /*11.0*/
|
||||
HB_SCRIPT_OLD_SOGDIAN = HB_TAG ('S','o','g','o'), /*11.0*/
|
||||
HB_SCRIPT_SOGDIAN = HB_TAG ('S','o','g','d'), /*11.0*/
|
||||
|
||||
/*
|
||||
* Since 2.4.0
|
||||
*/
|
||||
HB_SCRIPT_ELYMAIC = HB_TAG ('E','l','y','m'), /*12.0*/
|
||||
HB_SCRIPT_NANDINAGARI = HB_TAG ('N','a','n','d'), /*12.0*/
|
||||
HB_SCRIPT_NYIAKENG_PUACHUE_HMONG = HB_TAG ('H','m','n','p'), /*12.0*/
|
||||
HB_SCRIPT_WANCHO = HB_TAG ('W','c','h','o'), /*12.0*/
|
||||
|
||||
/*
|
||||
* Since 2.6.7
|
||||
*/
|
||||
HB_SCRIPT_CHORASMIAN = HB_TAG ('C','h','r','s'), /*13.0*/
|
||||
HB_SCRIPT_DIVES_AKURU = HB_TAG ('D','i','a','k'), /*13.0*/
|
||||
HB_SCRIPT_KHITAN_SMALL_SCRIPT = HB_TAG ('K','i','t','s'), /*13.0*/
|
||||
HB_SCRIPT_YEZIDI = HB_TAG ('Y','e','z','i'), /*13.0*/
|
||||
|
||||
/*
|
||||
* Since 3.0.0
|
||||
*/
|
||||
HB_SCRIPT_CYPRO_MINOAN = HB_TAG ('C','p','m','n'), /*14.0*/
|
||||
HB_SCRIPT_OLD_UYGHUR = HB_TAG ('O','u','g','r'), /*14.0*/
|
||||
HB_SCRIPT_TANGSA = HB_TAG ('T','n','s','a'), /*14.0*/
|
||||
HB_SCRIPT_TOTO = HB_TAG ('T','o','t','o'), /*14.0*/
|
||||
HB_SCRIPT_VITHKUQI = HB_TAG ('V','i','t','h'), /*14.0*/
|
||||
|
||||
/*
|
||||
* Since 3.4.0
|
||||
*/
|
||||
HB_SCRIPT_MATH = HB_TAG ('Z','m','t','h'),
|
||||
|
||||
/*
|
||||
* Since 5.2.0
|
||||
*/
|
||||
HB_SCRIPT_KAWI = HB_TAG ('K','a','w','i'), /*15.0*/
|
||||
HB_SCRIPT_NAG_MUNDARI = HB_TAG ('N','a','g','m'), /*15.0*/
|
||||
|
||||
/*
|
||||
* Since 10.0.0
|
||||
*/
|
||||
HB_SCRIPT_GARAY = HB_TAG ('G','a','r','a'), /*16.0*/
|
||||
HB_SCRIPT_GURUNG_KHEMA = HB_TAG ('G','u','k','h'), /*16.0*/
|
||||
HB_SCRIPT_KIRAT_RAI = HB_TAG ('K','r','a','i'), /*16.0*/
|
||||
HB_SCRIPT_OL_ONAL = HB_TAG ('O','n','a','o'), /*16.0*/
|
||||
HB_SCRIPT_SUNUWAR = HB_TAG ('S','u','n','u'), /*16.0*/
|
||||
HB_SCRIPT_TODHRI = HB_TAG ('T','o','d','r'), /*16.0*/
|
||||
HB_SCRIPT_TULU_TIGALARI = HB_TAG ('T','u','t','g'), /*16.0*/
|
||||
|
||||
/* No script set. */
|
||||
HB_SCRIPT_INVALID = HB_TAG_NONE,
|
||||
|
||||
/*< private >*/
|
||||
|
||||
/* Dummy values to ensure any hb_tag_t value can be passed/stored as hb_script_t
|
||||
* without risking undefined behavior. We have two, for historical reasons.
|
||||
* HB_TAG_MAX used to be unsigned, but that was invalid Ansi C, so was changed
|
||||
* to _HB_SCRIPT_MAX_VALUE to be equal to HB_TAG_MAX_SIGNED as well.
|
||||
*
|
||||
* See this thread for technicalities:
|
||||
*
|
||||
* https://lists.freedesktop.org/archives/harfbuzz/2014-March/004150.html
|
||||
*/
|
||||
_HB_SCRIPT_MAX_VALUE = HB_TAG_MAX_SIGNED, /*< skip >*/
|
||||
_HB_SCRIPT_MAX_VALUE_SIGNED = HB_TAG_MAX_SIGNED /*< skip >*/
|
||||
|
||||
} hb_script_t;
|
||||
|
||||
#include "hb-script-list.h"
|
||||
|
||||
/* Script functions */
|
||||
|
||||
|
@ -948,6 +519,16 @@ typedef struct hb_glyph_extents_t {
|
|||
*/
|
||||
typedef struct hb_font_t hb_font_t;
|
||||
|
||||
/* Not of much use to clients. */
|
||||
HB_EXTERN void*
|
||||
hb_malloc (size_t size);
|
||||
HB_EXTERN void*
|
||||
hb_calloc (size_t nmemb, size_t size);
|
||||
HB_EXTERN void*
|
||||
hb_realloc (void *ptr, size_t size);
|
||||
HB_EXTERN void
|
||||
hb_free (void *ptr);
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
#endif /* HB_COMMON_H */
|
||||
|
|
|
@ -146,6 +146,7 @@
|
|||
|
||||
#ifdef HB_NO_DRAW
|
||||
#define HB_NO_OUTLINE
|
||||
#define HB_NO_PAINT
|
||||
#endif
|
||||
|
||||
#ifdef HB_NO_GETENV
|
||||
|
@ -191,7 +192,6 @@
|
|||
#ifdef HB_MINIMIZE_MEMORY_USAGE
|
||||
#define HB_NO_GDEF_CACHE
|
||||
#define HB_NO_OT_LAYOUT_LOOKUP_CACHE
|
||||
#define HB_NO_OT_FONT_ADVANCE_CACHE
|
||||
#define HB_NO_OT_FONT_CMAP_CACHE
|
||||
#endif
|
||||
|
||||
|
|
|
@ -28,7 +28,8 @@
|
|||
|
||||
#ifdef HAVE_CORETEXT
|
||||
|
||||
#include "hb-coretext.h"
|
||||
#include "hb-coretext.hh"
|
||||
#include "hb-aat-layout-trak-table.hh"
|
||||
|
||||
#include "hb-draw.hh"
|
||||
#include "hb-font.hh"
|
||||
|
@ -42,24 +43,17 @@
|
|||
# define kCTFontOrientationVertical kCTFontVerticalOrientation
|
||||
#endif
|
||||
|
||||
#define MAX_GLYPHS 64u
|
||||
|
||||
static void
|
||||
_hb_coretext_font_destroy (void *font_data)
|
||||
{
|
||||
CTFontRef ct_font = (CTFontRef) font_data;
|
||||
|
||||
CFRelease (ct_font);
|
||||
}
|
||||
#define MAX_GLYPHS 256u
|
||||
|
||||
static hb_bool_t
|
||||
hb_coretext_get_nominal_glyph (hb_font_t *font HB_UNUSED,
|
||||
void *font_data,
|
||||
hb_coretext_get_nominal_glyph (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t unicode,
|
||||
hb_codepoint_t *glyph,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
CTFontRef ct_font = (CTFontRef) font_data;
|
||||
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
|
||||
|
||||
UniChar ch[2];
|
||||
CGGlyph cg_glyph[2];
|
||||
unsigned count = 0;
|
||||
|
@ -85,7 +79,7 @@ hb_coretext_get_nominal_glyph (hb_font_t *font HB_UNUSED,
|
|||
}
|
||||
|
||||
static unsigned int
|
||||
hb_coretext_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
|
||||
hb_coretext_get_nominal_glyphs (hb_font_t *font,
|
||||
void *font_data,
|
||||
unsigned int count,
|
||||
const hb_codepoint_t *first_unicode,
|
||||
|
@ -94,6 +88,8 @@ hb_coretext_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
|
|||
unsigned int glyph_stride,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
|
||||
|
||||
// If any non-BMP codepoint is requested, use the slow path.
|
||||
bool slow_path = false;
|
||||
auto *unicode = first_unicode;
|
||||
|
@ -119,8 +115,6 @@ hb_coretext_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
|
|||
return count;
|
||||
}
|
||||
|
||||
CTFontRef ct_font = (CTFontRef) font_data;
|
||||
|
||||
UniChar ch[MAX_GLYPHS];
|
||||
CGGlyph cg_glyph[MAX_GLYPHS];
|
||||
for (unsigned i = 0; i < count; i += MAX_GLYPHS)
|
||||
|
@ -152,14 +146,14 @@ hb_coretext_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
|
|||
}
|
||||
|
||||
static hb_bool_t
|
||||
hb_coretext_get_variation_glyph (hb_font_t *font HB_UNUSED,
|
||||
void *font_data,
|
||||
hb_coretext_get_variation_glyph (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t unicode,
|
||||
hb_codepoint_t variation_selector,
|
||||
hb_codepoint_t *glyph,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
CTFontRef ct_font = (CTFontRef) font_data;
|
||||
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
|
||||
|
||||
UniChar ch[4];
|
||||
CGGlyph cg_glyph[4];
|
||||
|
@ -194,12 +188,17 @@ hb_coretext_get_variation_glyph (hb_font_t *font HB_UNUSED,
|
|||
if (cg_glyph[i])
|
||||
return false;
|
||||
|
||||
// Humm. CoreText falls back to the default glyph if the variation selector
|
||||
// is not supported. We cannot truly detect that case. So, in essence,
|
||||
// we are always returning true here...
|
||||
|
||||
*glyph = cg_glyph[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
hb_coretext_get_glyph_h_advances (hb_font_t* font, void* font_data,
|
||||
hb_coretext_get_glyph_h_advances (hb_font_t* font,
|
||||
void* font_data HB_UNUSED,
|
||||
unsigned count,
|
||||
const hb_codepoint_t *first_glyph,
|
||||
unsigned glyph_stride,
|
||||
|
@ -207,10 +206,11 @@ hb_coretext_get_glyph_h_advances (hb_font_t* font, void* font_data,
|
|||
unsigned advance_stride,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
CTFontRef ct_font = (CTFontRef) font_data;
|
||||
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
|
||||
|
||||
CGFloat ct_font_size = CTFontGetSize (ct_font);
|
||||
CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
|
||||
hb_position_t tracking = font->face->table.trak->get_tracking (font, HB_DIRECTION_LTR, 0.f);
|
||||
|
||||
CGGlyph cg_glyph[MAX_GLYPHS];
|
||||
CGSize advances[MAX_GLYPHS];
|
||||
|
@ -225,7 +225,7 @@ hb_coretext_get_glyph_h_advances (hb_font_t* font, void* font_data,
|
|||
CTFontGetAdvancesForGlyphs (ct_font, kCTFontOrientationHorizontal, cg_glyph, advances, c);
|
||||
for (unsigned j = 0; j < c; j++)
|
||||
{
|
||||
*first_advance = round (advances[j].width * x_mult);
|
||||
*first_advance = round (advances[j].width * x_mult) - tracking;
|
||||
first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
|
||||
}
|
||||
}
|
||||
|
@ -233,7 +233,8 @@ hb_coretext_get_glyph_h_advances (hb_font_t* font, void* font_data,
|
|||
|
||||
#ifndef HB_NO_VERTICAL
|
||||
static void
|
||||
hb_coretext_get_glyph_v_advances (hb_font_t* font, void* font_data,
|
||||
hb_coretext_get_glyph_v_advances (hb_font_t* font,
|
||||
void* font_data HB_UNUSED,
|
||||
unsigned count,
|
||||
const hb_codepoint_t *first_glyph,
|
||||
unsigned glyph_stride,
|
||||
|
@ -241,10 +242,11 @@ hb_coretext_get_glyph_v_advances (hb_font_t* font, void* font_data,
|
|||
unsigned advance_stride,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
CTFontRef ct_font = (CTFontRef) font_data;
|
||||
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
|
||||
|
||||
CGFloat ct_font_size = CTFontGetSize (ct_font);
|
||||
CGFloat y_mult = (CGFloat) -font->y_scale / ct_font_size;
|
||||
hb_position_t tracking = font->face->table.trak->get_tracking (font, HB_DIRECTION_TTB, 0.f);
|
||||
|
||||
CGGlyph cg_glyph[MAX_GLYPHS];
|
||||
CGSize advances[MAX_GLYPHS];
|
||||
|
@ -259,23 +261,21 @@ hb_coretext_get_glyph_v_advances (hb_font_t* font, void* font_data,
|
|||
CTFontGetAdvancesForGlyphs (ct_font, kCTFontOrientationVertical, cg_glyph, advances, c);
|
||||
for (unsigned j = 0; j < c; j++)
|
||||
{
|
||||
*first_advance = round (advances[j].width * y_mult);
|
||||
*first_advance = round (advances[j].width * y_mult) - tracking;
|
||||
first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HB_NO_VERTICAL
|
||||
static hb_bool_t
|
||||
hb_coretext_get_glyph_v_origin (hb_font_t *font,
|
||||
void *font_data,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t glyph,
|
||||
hb_position_t *x,
|
||||
hb_position_t *y,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
CTFontRef ct_font = (CTFontRef) font_data;
|
||||
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
|
||||
|
||||
CGFloat ct_font_size = CTFontGetSize (ct_font);
|
||||
CGFloat x_mult = (CGFloat) -font->x_scale / ct_font_size;
|
||||
|
@ -294,12 +294,12 @@ hb_coretext_get_glyph_v_origin (hb_font_t *font,
|
|||
|
||||
static hb_bool_t
|
||||
hb_coretext_get_glyph_extents (hb_font_t *font,
|
||||
void *font_data,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t glyph,
|
||||
hb_glyph_extents_t *extents,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
CTFontRef ct_font = (CTFontRef) font_data;
|
||||
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
|
||||
|
||||
CGFloat ct_font_size = CTFontGetSize (ct_font);
|
||||
CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
|
||||
|
@ -310,20 +310,21 @@ hb_coretext_get_glyph_extents (hb_font_t *font,
|
|||
kCTFontOrientationDefault, glyphs, NULL, 1);
|
||||
|
||||
extents->x_bearing = round (bounds.origin.x * x_mult);
|
||||
extents->y_bearing = round (bounds.origin.y * y_mult);
|
||||
extents->y_bearing = round ((bounds.origin.y + bounds.size.height) * y_mult);
|
||||
extents->width = round (bounds.size.width * x_mult);
|
||||
extents->height = round (bounds.size.height * y_mult);
|
||||
extents->height = round (bounds.origin.y * y_mult) - extents->y_bearing;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
hb_coretext_get_font_h_extents (hb_font_t *font,
|
||||
void *font_data,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_font_extents_t *metrics,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
CTFontRef ct_font = (CTFontRef) font_data;
|
||||
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
|
||||
|
||||
CGFloat ct_font_size = CTFontGetSize (ct_font);
|
||||
CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size;
|
||||
|
||||
|
@ -371,7 +372,7 @@ hb_coretext_draw_glyph (hb_font_t *font,
|
|||
hb_draw_funcs_t *draw_funcs, void *draw_data,
|
||||
void *user_data)
|
||||
{
|
||||
CTFontRef ct_font = (CTFontRef) font_data;
|
||||
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
|
||||
|
||||
CGFloat ct_font_size = CTFontGetSize (ct_font);
|
||||
CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
|
||||
|
@ -415,17 +416,20 @@ hb_coretext_get_glyph_name (hb_font_t *font,
|
|||
(UInt8 *) name, size, &len);
|
||||
|
||||
name[len] = '\0';
|
||||
|
||||
CFRelease (cf_name);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
hb_coretext_get_glyph_from_name (hb_font_t *font HB_UNUSED,
|
||||
void *font_data,
|
||||
hb_coretext_get_glyph_from_name (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
const char *name, int len,
|
||||
hb_codepoint_t *glyph,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
CTFontRef ct_font = (CTFontRef) font_data;
|
||||
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
|
||||
|
||||
if (len == -1)
|
||||
len = strlen (name);
|
||||
|
@ -458,10 +462,8 @@ static struct hb_coretext_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t
|
|||
|
||||
hb_font_funcs_set_font_h_extents_func (funcs, hb_coretext_get_font_h_extents, nullptr, nullptr);
|
||||
hb_font_funcs_set_glyph_h_advances_func (funcs, hb_coretext_get_glyph_h_advances, nullptr, nullptr);
|
||||
//hb_font_funcs_set_glyph_h_origin_func (funcs, hb_coretext_get_glyph_h_origin, nullptr, nullptr);
|
||||
|
||||
#ifndef HB_NO_VERTICAL
|
||||
//hb_font_funcs_set_font_v_extents_func (funcs, hb_coretext_get_font_v_extents, nullptr, nullptr);
|
||||
hb_font_funcs_set_glyph_v_advances_func (funcs, hb_coretext_get_glyph_v_advances, nullptr, nullptr);
|
||||
hb_font_funcs_set_glyph_v_origin_func (funcs, hb_coretext_get_glyph_v_origin, nullptr, nullptr);
|
||||
#endif
|
||||
|
@ -530,8 +532,7 @@ hb_coretext_font_set_funcs (hb_font_t *font)
|
|||
|
||||
hb_font_set_funcs (font,
|
||||
_hb_coretext_get_font_funcs (),
|
||||
(void *) CFRetain (ct_font),
|
||||
_hb_coretext_font_destroy);
|
||||
nullptr, nullptr);
|
||||
}
|
||||
|
||||
#undef MAX_GLYPHS
|
||||
|
|
|
@ -32,279 +32,9 @@
|
|||
|
||||
#include "hb-shaper-impl.hh"
|
||||
|
||||
#include "hb-coretext.h"
|
||||
#include "hb-coretext.hh"
|
||||
#include "hb-aat-layout.hh"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-coretext
|
||||
* @title: hb-coretext
|
||||
* @short_description: CoreText integration
|
||||
* @include: hb-coretext.h
|
||||
*
|
||||
* Functions for using HarfBuzz with the CoreText fonts.
|
||||
**/
|
||||
|
||||
static CTFontRef create_ct_font (CGFontRef cg_font, CGFloat font_size);
|
||||
|
||||
static void
|
||||
release_table_data (void *user_data)
|
||||
{
|
||||
CFDataRef cf_data = reinterpret_cast<CFDataRef> (user_data);
|
||||
CFRelease(cf_data);
|
||||
}
|
||||
|
||||
static hb_blob_t *
|
||||
_hb_cg_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
|
||||
{
|
||||
CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
|
||||
CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
|
||||
if (unlikely (!cf_data))
|
||||
return nullptr;
|
||||
|
||||
const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data));
|
||||
const size_t length = CFDataGetLength (cf_data);
|
||||
if (!data || !length)
|
||||
{
|
||||
CFRelease (cf_data);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY,
|
||||
reinterpret_cast<void *> (const_cast<__CFData *> (cf_data)),
|
||||
release_table_data);
|
||||
}
|
||||
|
||||
static unsigned
|
||||
_hb_cg_get_table_tags (const hb_face_t *face HB_UNUSED,
|
||||
unsigned int start_offset,
|
||||
unsigned int *table_count,
|
||||
hb_tag_t *table_tags,
|
||||
void *user_data)
|
||||
{
|
||||
CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
|
||||
|
||||
CTFontRef ct_font = create_ct_font (cg_font, (CGFloat) HB_CORETEXT_DEFAULT_FONT_SIZE);
|
||||
|
||||
auto arr = CTFontCopyAvailableTables (ct_font, kCTFontTableOptionNoOptions);
|
||||
|
||||
unsigned population = (unsigned) CFArrayGetCount (arr);
|
||||
unsigned end_offset;
|
||||
|
||||
if (!table_count)
|
||||
goto done;
|
||||
|
||||
if (unlikely (start_offset >= population))
|
||||
{
|
||||
*table_count = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
end_offset = start_offset + *table_count;
|
||||
if (unlikely (end_offset < start_offset))
|
||||
{
|
||||
*table_count = 0;
|
||||
goto done;
|
||||
}
|
||||
end_offset= hb_min (end_offset, (unsigned) population);
|
||||
|
||||
*table_count = end_offset - start_offset;
|
||||
for (unsigned i = start_offset; i < end_offset; i++)
|
||||
{
|
||||
CTFontTableTag tag = (CTFontTableTag)(uintptr_t) CFArrayGetValueAtIndex (arr, i);
|
||||
table_tags[i - start_offset] = tag;
|
||||
}
|
||||
|
||||
done:
|
||||
CFRelease (arr);
|
||||
CFRelease (ct_font);
|
||||
return population;
|
||||
}
|
||||
|
||||
static void
|
||||
_hb_cg_font_release (void *data)
|
||||
{
|
||||
CGFontRelease ((CGFontRef) data);
|
||||
}
|
||||
|
||||
|
||||
static CTFontDescriptorRef
|
||||
get_last_resort_font_desc ()
|
||||
{
|
||||
// TODO Handle allocation failures?
|
||||
CTFontDescriptorRef last_resort = CTFontDescriptorCreateWithNameAndSize (CFSTR("LastResort"), 0);
|
||||
CFArrayRef cascade_list = CFArrayCreate (kCFAllocatorDefault,
|
||||
(const void **) &last_resort,
|
||||
1,
|
||||
&kCFTypeArrayCallBacks);
|
||||
CFRelease (last_resort);
|
||||
CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
|
||||
(const void **) &kCTFontCascadeListAttribute,
|
||||
(const void **) &cascade_list,
|
||||
1,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
CFRelease (cascade_list);
|
||||
|
||||
CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
|
||||
CFRelease (attributes);
|
||||
return font_desc;
|
||||
}
|
||||
|
||||
static void
|
||||
release_data (void *info, const void *data, size_t size)
|
||||
{
|
||||
assert (hb_blob_get_length ((hb_blob_t *) info) == size &&
|
||||
hb_blob_get_data ((hb_blob_t *) info, nullptr) == data);
|
||||
|
||||
hb_blob_destroy ((hb_blob_t *) info);
|
||||
}
|
||||
|
||||
static CGFontRef
|
||||
create_cg_font (hb_face_t *face)
|
||||
{
|
||||
CGFontRef cg_font = nullptr;
|
||||
if (face->destroy == _hb_cg_font_release)
|
||||
{
|
||||
cg_font = CGFontRetain ((CGFontRef) face->user_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
hb_blob_t *blob = hb_face_reference_blob (face);
|
||||
unsigned int blob_length;
|
||||
const char *blob_data = hb_blob_get_data (blob, &blob_length);
|
||||
if (unlikely (!blob_length))
|
||||
DEBUG_MSG (CORETEXT, face, "Face has empty blob");
|
||||
|
||||
CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
|
||||
if (likely (provider))
|
||||
{
|
||||
cg_font = CGFontCreateWithDataProvider (provider);
|
||||
if (unlikely (!cg_font))
|
||||
DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
|
||||
CGDataProviderRelease (provider);
|
||||
}
|
||||
}
|
||||
return cg_font;
|
||||
}
|
||||
|
||||
static CTFontRef
|
||||
create_ct_font (CGFontRef cg_font, CGFloat font_size)
|
||||
{
|
||||
CTFontRef ct_font = nullptr;
|
||||
|
||||
/* CoreText does not enable trak table usage / tracking when creating a CTFont
|
||||
* using CTFontCreateWithGraphicsFont. The only way of enabling tracking seems
|
||||
* to be through the CTFontCreateUIFontForLanguage call. */
|
||||
CFStringRef cg_postscript_name = CGFontCopyPostScriptName (cg_font);
|
||||
if (CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSText")) ||
|
||||
CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSDisplay")))
|
||||
{
|
||||
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1080
|
||||
# define kCTFontUIFontSystem kCTFontSystemFontType
|
||||
# define kCTFontUIFontEmphasizedSystem kCTFontEmphasizedSystemFontType
|
||||
#endif
|
||||
CTFontUIFontType font_type = kCTFontUIFontSystem;
|
||||
if (CFStringHasSuffix (cg_postscript_name, CFSTR ("-Bold")))
|
||||
font_type = kCTFontUIFontEmphasizedSystem;
|
||||
|
||||
ct_font = CTFontCreateUIFontForLanguage (font_type, font_size, nullptr);
|
||||
CFStringRef ct_result_name = CTFontCopyPostScriptName(ct_font);
|
||||
if (CFStringCompare (ct_result_name, cg_postscript_name, 0) != kCFCompareEqualTo)
|
||||
{
|
||||
CFRelease(ct_font);
|
||||
ct_font = nullptr;
|
||||
}
|
||||
CFRelease (ct_result_name);
|
||||
}
|
||||
CFRelease (cg_postscript_name);
|
||||
|
||||
if (!ct_font)
|
||||
ct_font = CTFontCreateWithGraphicsFont (cg_font, font_size, nullptr, nullptr);
|
||||
|
||||
if (unlikely (!ct_font)) {
|
||||
DEBUG_MSG (CORETEXT, cg_font, "Font CTFontCreateWithGraphicsFont() failed");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* crbug.com/576941 and crbug.com/625902 and the investigation in the latter
|
||||
* bug indicate that the cascade list reconfiguration occasionally causes
|
||||
* crashes in CoreText on OS X 10.9, thus let's skip this step on older
|
||||
* operating system versions. Except for the emoji font, where _not_
|
||||
* reconfiguring the cascade list causes CoreText crashes. For details, see
|
||||
* crbug.com/549610 */
|
||||
// 0x00070000 stands for "kCTVersionNumber10_10", see CoreText.h
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
if (&CTGetCoreTextVersion != nullptr && CTGetCoreTextVersion() < 0x00070000) {
|
||||
#pragma GCC diagnostic pop
|
||||
CFStringRef fontName = CTFontCopyPostScriptName (ct_font);
|
||||
bool isEmojiFont = CFStringCompare (fontName, CFSTR("AppleColorEmoji"), 0) == kCFCompareEqualTo;
|
||||
CFRelease (fontName);
|
||||
if (!isEmojiFont)
|
||||
return ct_font;
|
||||
}
|
||||
|
||||
CFURLRef original_url = nullptr;
|
||||
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
|
||||
ATSFontRef atsFont;
|
||||
FSRef fsref;
|
||||
OSStatus status;
|
||||
atsFont = CTFontGetPlatformFont (ct_font, NULL);
|
||||
status = ATSFontGetFileReference (atsFont, &fsref);
|
||||
if (status == noErr)
|
||||
original_url = CFURLCreateFromFSRef (NULL, &fsref);
|
||||
#else
|
||||
original_url = (CFURLRef) CTFontCopyAttribute (ct_font, kCTFontURLAttribute);
|
||||
#endif
|
||||
|
||||
/* Create font copy with cascade list that has LastResort first; this speeds up CoreText
|
||||
* font fallback which we don't need anyway. */
|
||||
{
|
||||
CTFontDescriptorRef last_resort_font_desc = get_last_resort_font_desc ();
|
||||
CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0.0, nullptr, last_resort_font_desc);
|
||||
CFRelease (last_resort_font_desc);
|
||||
if (new_ct_font)
|
||||
{
|
||||
/* The CTFontCreateCopyWithAttributes call fails to stay on the same font
|
||||
* when reconfiguring the cascade list and may switch to a different font
|
||||
* when there are fonts that go by the same name, since the descriptor is
|
||||
* just name and size.
|
||||
*
|
||||
* Avoid reconfiguring the cascade lists if the new font is outside the
|
||||
* system locations that we cannot access from the sandboxed renderer
|
||||
* process in Blink. This can be detected by the new file URL location
|
||||
* that the newly found font points to. */
|
||||
CFURLRef new_url = nullptr;
|
||||
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
|
||||
atsFont = CTFontGetPlatformFont (new_ct_font, NULL);
|
||||
status = ATSFontGetFileReference (atsFont, &fsref);
|
||||
if (status == noErr)
|
||||
new_url = CFURLCreateFromFSRef (NULL, &fsref);
|
||||
#else
|
||||
new_url = (CFURLRef) CTFontCopyAttribute (new_ct_font, kCTFontURLAttribute);
|
||||
#endif
|
||||
// Keep reconfigured font if URL cannot be retrieved (seems to be the case
|
||||
// on Mac OS 10.12 Sierra), speculative fix for crbug.com/625606
|
||||
if (!original_url || !new_url || CFEqual (original_url, new_url)) {
|
||||
CFRelease (ct_font);
|
||||
ct_font = new_ct_font;
|
||||
} else {
|
||||
CFRelease (new_ct_font);
|
||||
DEBUG_MSG (CORETEXT, ct_font, "Discarding reconfigured CTFont, location changed.");
|
||||
}
|
||||
if (new_url)
|
||||
CFRelease (new_url);
|
||||
}
|
||||
else
|
||||
DEBUG_MSG (CORETEXT, ct_font, "Font copy with empty cascade list failed");
|
||||
}
|
||||
|
||||
if (original_url)
|
||||
CFRelease (original_url);
|
||||
return ct_font;
|
||||
}
|
||||
|
||||
hb_coretext_face_data_t *
|
||||
_hb_coretext_shaper_face_data_create (hb_face_t *face)
|
||||
{
|
||||
|
@ -325,102 +55,6 @@ _hb_coretext_shaper_face_data_destroy (hb_coretext_face_data_t *data)
|
|||
CFRelease ((CGFontRef) data);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_coretext_face_create:
|
||||
* @cg_font: The CGFontRef to work upon
|
||||
*
|
||||
* Creates an #hb_face_t face object from the specified
|
||||
* CGFontRef.
|
||||
*
|
||||
* Return value: (transfer full): The new face object
|
||||
*
|
||||
* Since: 0.9.10
|
||||
*/
|
||||
hb_face_t *
|
||||
hb_coretext_face_create (CGFontRef cg_font)
|
||||
{
|
||||
hb_face_t *face = hb_face_create_for_tables (_hb_cg_reference_table, CGFontRetain (cg_font), _hb_cg_font_release);
|
||||
hb_face_set_get_table_tags_func (face, _hb_cg_get_table_tags, cg_font, nullptr);
|
||||
return face;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_coretext_face_create_from_file_or_fail:
|
||||
* @file_name: A font filename
|
||||
* @index: The index of the face within the file
|
||||
*
|
||||
* Creates an #hb_face_t face object from the specified
|
||||
* font file and face index.
|
||||
*
|
||||
* This is similar in functionality to hb_face_create_from_file_or_fail(),
|
||||
* but uses the CoreText library for loading the font file.
|
||||
*
|
||||
* Return value: (transfer full): The new face object, or `NULL` if
|
||||
* no face is found at the specified index or the file cannot be read.
|
||||
*
|
||||
* Since: 10.1.0
|
||||
*/
|
||||
hb_face_t *
|
||||
hb_coretext_face_create_from_file_or_fail (const char *file_name,
|
||||
unsigned int index)
|
||||
{
|
||||
auto url = CFURLCreateFromFileSystemRepresentation (nullptr,
|
||||
(const UInt8 *) file_name,
|
||||
strlen (file_name),
|
||||
false);
|
||||
if (unlikely (!url))
|
||||
return nullptr;
|
||||
|
||||
auto ct_font_desc_array = CTFontManagerCreateFontDescriptorsFromURL (url);
|
||||
if (unlikely (!ct_font_desc_array))
|
||||
{
|
||||
CFRelease (url);
|
||||
return nullptr;
|
||||
}
|
||||
auto ct_font_desc = (CFArrayGetCount (ct_font_desc_array) > index) ?
|
||||
(CTFontDescriptorRef) CFArrayGetValueAtIndex (ct_font_desc_array, index) : nullptr;
|
||||
if (unlikely (!ct_font_desc))
|
||||
{
|
||||
CFRelease (ct_font_desc_array);
|
||||
CFRelease (url);
|
||||
return nullptr;
|
||||
}
|
||||
CFRelease (url);
|
||||
auto ct_font = ct_font_desc ? CTFontCreateWithFontDescriptor (ct_font_desc, 0, nullptr) : nullptr;
|
||||
CFRelease (ct_font_desc_array);
|
||||
if (unlikely (!ct_font))
|
||||
return nullptr;
|
||||
|
||||
auto cg_font = ct_font ? CTFontCopyGraphicsFont (ct_font, nullptr) : nullptr;
|
||||
CFRelease (ct_font);
|
||||
if (unlikely (!cg_font))
|
||||
return nullptr;
|
||||
|
||||
hb_face_t *face = hb_coretext_face_create (cg_font);
|
||||
CFRelease (cg_font);
|
||||
if (unlikely (hb_face_is_immutable (face)))
|
||||
return nullptr;
|
||||
|
||||
return face;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_coretext_face_get_cg_font:
|
||||
* @face: The #hb_face_t to work upon
|
||||
*
|
||||
* Fetches the CGFontRef associated with an #hb_face_t
|
||||
* face object
|
||||
*
|
||||
* Return value: the CGFontRef found
|
||||
*
|
||||
* Since: 0.9.10
|
||||
*/
|
||||
CGFontRef
|
||||
hb_coretext_face_get_cg_font (hb_face_t *face)
|
||||
{
|
||||
return (CGFontRef) (const void *) face->data.coretext;
|
||||
}
|
||||
|
||||
|
||||
hb_coretext_font_data_t *
|
||||
_hb_coretext_shaper_font_data_create (hb_font_t *font)
|
||||
|
@ -439,7 +73,9 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (font->num_coords)
|
||||
unsigned num_axes = hb_ot_var_get_axis_count (face);
|
||||
// https://github.com/harfbuzz/harfbuzz/issues/5163
|
||||
if (num_axes)
|
||||
{
|
||||
CFMutableDictionaryRef variations =
|
||||
CFDictionaryCreateMutable (kCFAllocatorDefault,
|
||||
|
@ -447,14 +83,15 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font)
|
|||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
|
||||
for (unsigned i = 0; i < font->num_coords; i++)
|
||||
unsigned count = hb_max (num_axes, font->num_coords);
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
{
|
||||
hb_ot_var_axis_info_t info;
|
||||
unsigned int c = 1;
|
||||
hb_ot_var_get_axis_infos (font->face, i, &c, &info);
|
||||
if (font->design_coords[i] == info.default_value)
|
||||
continue;
|
||||
float v = hb_clamp (font->design_coords[i], info.min_value, info.max_value);
|
||||
float v = i < font->num_coords ?
|
||||
hb_clamp (font->design_coords[i], info.min_value, info.max_value) :
|
||||
info.default_value;
|
||||
|
||||
CFNumberRef tag_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &info.tag);
|
||||
CFNumberRef value_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberFloatType, &v);
|
||||
|
@ -489,94 +126,6 @@ _hb_coretext_shaper_font_data_destroy (hb_coretext_font_data_t *data)
|
|||
CFRelease ((CTFontRef) data);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_coretext_font_create:
|
||||
* @ct_font: The CTFontRef to work upon
|
||||
*
|
||||
* Creates an #hb_font_t font object from the specified
|
||||
* CTFontRef.
|
||||
*
|
||||
* The created font uses the default font functions implemented
|
||||
* natively by HarfBuzz. If you want to use the CoreText font functions
|
||||
* instead (rarely needed), you can do so by calling
|
||||
* by hb_coretext_font_set_funcs().
|
||||
*
|
||||
* Return value: (transfer full): The new font object
|
||||
*
|
||||
* Since: 1.7.2
|
||||
**/
|
||||
hb_font_t *
|
||||
hb_coretext_font_create (CTFontRef ct_font)
|
||||
{
|
||||
CGFontRef cg_font = CTFontCopyGraphicsFont (ct_font, nullptr);
|
||||
hb_face_t *face = hb_coretext_face_create (cg_font);
|
||||
CFRelease (cg_font);
|
||||
hb_font_t *font = hb_font_create (face);
|
||||
hb_face_destroy (face);
|
||||
|
||||
if (unlikely (hb_object_is_immutable (font)))
|
||||
return font;
|
||||
|
||||
hb_font_set_ptem (font, CTFontGetSize (ct_font));
|
||||
|
||||
/* Copy font variations */
|
||||
CFDictionaryRef variations = CTFontCopyVariation (ct_font);
|
||||
if (variations)
|
||||
{
|
||||
hb_vector_t<hb_variation_t> vars;
|
||||
hb_vector_t<CFTypeRef> keys;
|
||||
hb_vector_t<CFTypeRef> values;
|
||||
|
||||
CFIndex count = CFDictionaryGetCount (variations);
|
||||
if (unlikely (!vars.alloc_exact (count) || !keys.resize_exact (count) || !values.resize_exact (count)))
|
||||
goto done;
|
||||
|
||||
// Fetch them one by one and collect in a vector of our own.
|
||||
CFDictionaryGetKeysAndValues (variations, keys.arrayZ, values.arrayZ);
|
||||
for (CFIndex i = 0; i < count; i++)
|
||||
{
|
||||
int tag;
|
||||
float value;
|
||||
CFNumberGetValue ((CFNumberRef) keys.arrayZ[i], kCFNumberIntType, &tag);
|
||||
CFNumberGetValue ((CFNumberRef) values.arrayZ[i], kCFNumberFloatType, &value);
|
||||
|
||||
hb_variation_t var = {tag, value};
|
||||
vars.push (var);
|
||||
}
|
||||
hb_font_set_variations (font, vars.arrayZ, vars.length);
|
||||
|
||||
done:
|
||||
CFRelease (variations);
|
||||
}
|
||||
|
||||
/* Let there be dragons here... */
|
||||
font->data.coretext.cmpexch (nullptr, (hb_coretext_font_data_t *) CFRetain (ct_font));
|
||||
|
||||
// https://github.com/harfbuzz/harfbuzz/pull/4895#issuecomment-2408471254
|
||||
//hb_coretext_font_set_funcs (font);
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_coretext_font_get_ct_font:
|
||||
* @font: #hb_font_t to work upon
|
||||
*
|
||||
* Fetches the CTFontRef associated with the specified
|
||||
* #hb_font_t font object.
|
||||
*
|
||||
* Return value: the CTFontRef found
|
||||
*
|
||||
* Since: 0.9.10
|
||||
*/
|
||||
CTFontRef
|
||||
hb_coretext_font_get_ct_font (hb_font_t *font)
|
||||
{
|
||||
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
|
||||
return ct_font ? (CTFontRef) ct_font : nullptr;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* shaper
|
||||
*/
|
||||
|
@ -646,7 +195,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
|
|||
* B1 M1 B2 M2, and B1-B2 form a ligature, M2's cluster will
|
||||
* continue pointing to B2 even though B2 was merged into B1's
|
||||
* cluster... */
|
||||
if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
|
||||
if (HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES (buffer->cluster_level))
|
||||
{
|
||||
hb_unicode_funcs_t *unicode = buffer->unicode;
|
||||
unsigned int count = buffer->len;
|
||||
|
@ -1010,7 +559,7 @@ resize_and_retry:
|
|||
|
||||
CFArrayRef glyph_runs = CTLineGetGlyphRuns (line);
|
||||
unsigned int num_runs = CFArrayGetCount (glyph_runs);
|
||||
DEBUG_MSG (CORETEXT, nullptr, "Num runs: %d", num_runs);
|
||||
DEBUG_MSG (CORETEXT, nullptr, "Num runs: %u", num_runs);
|
||||
|
||||
buffer->len = 0;
|
||||
uint32_t status_or = 0;
|
||||
|
@ -1292,7 +841,7 @@ resize_and_retry:
|
|||
* or the native OT backend, only that the cluster indices will be
|
||||
* monotonic in the output buffer. */
|
||||
if (count > 1 && (status_or & kCTRunStatusNonMonotonic) &&
|
||||
buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
|
||||
HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (buffer->cluster_level))
|
||||
{
|
||||
hb_glyph_info_t *info = buffer->info;
|
||||
if (HB_DIRECTION_IS_FORWARD (buffer->props.direction))
|
||||
|
|
572
src/hb-coretext.cc
Normal file
572
src/hb-coretext.cc
Normal file
|
@ -0,0 +1,572 @@
|
|||
/*
|
||||
* Copyright © 2012,2013 Mozilla Foundation.
|
||||
* Copyright © 2012,2013 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Mozilla Author(s): Jonathan Kew
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#ifdef HAVE_CORETEXT
|
||||
|
||||
#include "hb-shaper-impl.hh"
|
||||
|
||||
#include "hb-coretext.hh"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-coretext
|
||||
* @title: hb-coretext
|
||||
* @short_description: CoreText integration
|
||||
* @include: hb-coretext.h
|
||||
*
|
||||
* Functions for using HarfBuzz with the CoreText fonts.
|
||||
**/
|
||||
|
||||
static void
|
||||
release_table_data (void *user_data)
|
||||
{
|
||||
CFDataRef cf_data = reinterpret_cast<CFDataRef> (user_data);
|
||||
CFRelease(cf_data);
|
||||
}
|
||||
|
||||
static hb_blob_t *
|
||||
_hb_cg_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
|
||||
{
|
||||
CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
|
||||
CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
|
||||
if (unlikely (!cf_data))
|
||||
return nullptr;
|
||||
|
||||
const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data));
|
||||
const size_t length = CFDataGetLength (cf_data);
|
||||
if (!data || !length)
|
||||
{
|
||||
CFRelease (cf_data);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY,
|
||||
reinterpret_cast<void *> (const_cast<__CFData *> (cf_data)),
|
||||
release_table_data);
|
||||
}
|
||||
|
||||
static unsigned
|
||||
_hb_cg_get_table_tags (const hb_face_t *face HB_UNUSED,
|
||||
unsigned int start_offset,
|
||||
unsigned int *table_count,
|
||||
hb_tag_t *table_tags,
|
||||
void *user_data)
|
||||
{
|
||||
CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
|
||||
|
||||
CTFontRef ct_font = create_ct_font (cg_font, (CGFloat) HB_CORETEXT_DEFAULT_FONT_SIZE);
|
||||
|
||||
auto arr = CTFontCopyAvailableTables (ct_font, kCTFontTableOptionNoOptions);
|
||||
|
||||
unsigned population = (unsigned) CFArrayGetCount (arr);
|
||||
unsigned end_offset;
|
||||
|
||||
if (!table_count)
|
||||
goto done;
|
||||
|
||||
if (unlikely (start_offset >= population))
|
||||
{
|
||||
*table_count = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
end_offset = start_offset + *table_count;
|
||||
if (unlikely (end_offset < start_offset))
|
||||
{
|
||||
*table_count = 0;
|
||||
goto done;
|
||||
}
|
||||
end_offset= hb_min (end_offset, (unsigned) population);
|
||||
|
||||
*table_count = end_offset - start_offset;
|
||||
for (unsigned i = start_offset; i < end_offset; i++)
|
||||
{
|
||||
CTFontTableTag tag = (CTFontTableTag)(uintptr_t) CFArrayGetValueAtIndex (arr, i);
|
||||
table_tags[i - start_offset] = tag;
|
||||
}
|
||||
|
||||
done:
|
||||
CFRelease (arr);
|
||||
CFRelease (ct_font);
|
||||
return population;
|
||||
}
|
||||
|
||||
static void
|
||||
_hb_cg_font_release (void *data)
|
||||
{
|
||||
CGFontRelease ((CGFontRef) data);
|
||||
}
|
||||
|
||||
|
||||
static CTFontDescriptorRef
|
||||
get_last_resort_font_desc ()
|
||||
{
|
||||
// TODO Handle allocation failures?
|
||||
CTFontDescriptorRef last_resort = CTFontDescriptorCreateWithNameAndSize (CFSTR("LastResort"), 0);
|
||||
CFArrayRef cascade_list = CFArrayCreate (kCFAllocatorDefault,
|
||||
(const void **) &last_resort,
|
||||
1,
|
||||
&kCFTypeArrayCallBacks);
|
||||
CFRelease (last_resort);
|
||||
CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
|
||||
(const void **) &kCTFontCascadeListAttribute,
|
||||
(const void **) &cascade_list,
|
||||
1,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
CFRelease (cascade_list);
|
||||
|
||||
CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
|
||||
CFRelease (attributes);
|
||||
return font_desc;
|
||||
}
|
||||
|
||||
static void
|
||||
release_data (void *info, const void *data, size_t size)
|
||||
{
|
||||
assert (hb_blob_get_length ((hb_blob_t *) info) == size &&
|
||||
hb_blob_get_data ((hb_blob_t *) info, nullptr) == data);
|
||||
|
||||
hb_blob_destroy ((hb_blob_t *) info);
|
||||
}
|
||||
|
||||
CGFontRef
|
||||
create_cg_font (CFArrayRef ct_font_desc_array, unsigned int named_instance_index)
|
||||
{
|
||||
if (named_instance_index == 0)
|
||||
{
|
||||
// Default instance. We don't know which one is it. Return the first one.
|
||||
// We will set the correct variations on it later.
|
||||
}
|
||||
else
|
||||
named_instance_index--;
|
||||
auto ct_font_desc = (CFArrayGetCount (ct_font_desc_array) > named_instance_index) ?
|
||||
(CTFontDescriptorRef) CFArrayGetValueAtIndex (ct_font_desc_array, named_instance_index) : nullptr;
|
||||
if (unlikely (!ct_font_desc))
|
||||
{
|
||||
CFRelease (ct_font_desc_array);
|
||||
return nullptr;
|
||||
}
|
||||
auto ct_font = ct_font_desc ? CTFontCreateWithFontDescriptor (ct_font_desc, 0, nullptr) : nullptr;
|
||||
CFRelease (ct_font_desc_array);
|
||||
if (unlikely (!ct_font))
|
||||
return nullptr;
|
||||
|
||||
auto cg_font = ct_font ? CTFontCopyGraphicsFont (ct_font, nullptr) : nullptr;
|
||||
CFRelease (ct_font);
|
||||
|
||||
return cg_font;
|
||||
}
|
||||
|
||||
CGFontRef
|
||||
create_cg_font (hb_blob_t *blob, unsigned int index)
|
||||
{
|
||||
hb_blob_make_immutable (blob);
|
||||
unsigned int blob_length;
|
||||
const char *blob_data = hb_blob_get_data (blob, &blob_length);
|
||||
if (unlikely (!blob_length))
|
||||
DEBUG_MSG (CORETEXT, blob, "Empty blob");
|
||||
|
||||
unsigned ttc_index = index & 0xFFFF;
|
||||
unsigned named_instance_index = index >> 16;
|
||||
|
||||
if (ttc_index != 0)
|
||||
{
|
||||
DEBUG_MSG (CORETEXT, blob, "TTC index %u not supported", ttc_index);
|
||||
return nullptr; // CoreText does not support TTCs
|
||||
}
|
||||
|
||||
if (unlikely (named_instance_index != 0))
|
||||
{
|
||||
auto ct_font_desc_array = CTFontManagerCreateFontDescriptorsFromData (CFDataCreate (kCFAllocatorDefault, (const UInt8 *) blob_data, blob_length));
|
||||
if (unlikely (!ct_font_desc_array))
|
||||
return nullptr;
|
||||
return create_cg_font (ct_font_desc_array, named_instance_index);
|
||||
}
|
||||
|
||||
hb_blob_reference (blob);
|
||||
CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
|
||||
CGFontRef cg_font = nullptr;
|
||||
if (likely (provider))
|
||||
{
|
||||
cg_font = CGFontCreateWithDataProvider (provider);
|
||||
if (unlikely (!cg_font))
|
||||
DEBUG_MSG (CORETEXT, blob, "CGFontCreateWithDataProvider() failed");
|
||||
CGDataProviderRelease (provider);
|
||||
}
|
||||
return cg_font;
|
||||
}
|
||||
|
||||
CGFontRef
|
||||
create_cg_font (hb_face_t *face)
|
||||
{
|
||||
CGFontRef cg_font = nullptr;
|
||||
if (face->destroy == _hb_cg_font_release)
|
||||
cg_font = CGFontRetain ((CGFontRef) face->user_data);
|
||||
else
|
||||
{
|
||||
hb_blob_t *blob = hb_face_reference_blob (face);
|
||||
cg_font = create_cg_font (blob, face->index);
|
||||
hb_blob_destroy (blob);
|
||||
}
|
||||
return cg_font;
|
||||
}
|
||||
|
||||
CTFontRef
|
||||
create_ct_font (CGFontRef cg_font, CGFloat font_size)
|
||||
{
|
||||
CTFontRef ct_font = nullptr;
|
||||
|
||||
/* CoreText does not enable trak table usage / tracking when creating a CTFont
|
||||
* using CTFontCreateWithGraphicsFont. The only way of enabling tracking seems
|
||||
* to be through the CTFontCreateUIFontForLanguage call. */
|
||||
CFStringRef cg_postscript_name = CGFontCopyPostScriptName (cg_font);
|
||||
if (CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSText")) ||
|
||||
CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSDisplay")))
|
||||
{
|
||||
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1080
|
||||
# define kCTFontUIFontSystem kCTFontSystemFontType
|
||||
# define kCTFontUIFontEmphasizedSystem kCTFontEmphasizedSystemFontType
|
||||
#endif
|
||||
CTFontUIFontType font_type = kCTFontUIFontSystem;
|
||||
if (CFStringHasSuffix (cg_postscript_name, CFSTR ("-Bold")))
|
||||
font_type = kCTFontUIFontEmphasizedSystem;
|
||||
|
||||
ct_font = CTFontCreateUIFontForLanguage (font_type, font_size, nullptr);
|
||||
CFStringRef ct_result_name = CTFontCopyPostScriptName(ct_font);
|
||||
if (CFStringCompare (ct_result_name, cg_postscript_name, 0) != kCFCompareEqualTo)
|
||||
{
|
||||
CFRelease(ct_font);
|
||||
ct_font = nullptr;
|
||||
}
|
||||
CFRelease (ct_result_name);
|
||||
}
|
||||
CFRelease (cg_postscript_name);
|
||||
|
||||
if (!ct_font)
|
||||
ct_font = CTFontCreateWithGraphicsFont (cg_font, font_size, nullptr, nullptr);
|
||||
|
||||
if (unlikely (!ct_font)) {
|
||||
DEBUG_MSG (CORETEXT, cg_font, "Font CTFontCreateWithGraphicsFont() failed");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* crbug.com/576941 and crbug.com/625902 and the investigation in the latter
|
||||
* bug indicate that the cascade list reconfiguration occasionally causes
|
||||
* crashes in CoreText on OS X 10.9, thus let's skip this step on older
|
||||
* operating system versions. Except for the emoji font, where _not_
|
||||
* reconfiguring the cascade list causes CoreText crashes. For details, see
|
||||
* crbug.com/549610 */
|
||||
// 0x00070000 stands for "kCTVersionNumber10_10", see CoreText.h
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
if (&CTGetCoreTextVersion != nullptr && CTGetCoreTextVersion() < 0x00070000) {
|
||||
#pragma GCC diagnostic pop
|
||||
CFStringRef fontName = CTFontCopyPostScriptName (ct_font);
|
||||
bool isEmojiFont = CFStringCompare (fontName, CFSTR("AppleColorEmoji"), 0) == kCFCompareEqualTo;
|
||||
CFRelease (fontName);
|
||||
if (!isEmojiFont)
|
||||
return ct_font;
|
||||
}
|
||||
|
||||
CFURLRef original_url = nullptr;
|
||||
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
|
||||
ATSFontRef atsFont;
|
||||
FSRef fsref;
|
||||
OSStatus status;
|
||||
atsFont = CTFontGetPlatformFont (ct_font, NULL);
|
||||
status = ATSFontGetFileReference (atsFont, &fsref);
|
||||
if (status == noErr)
|
||||
original_url = CFURLCreateFromFSRef (NULL, &fsref);
|
||||
#else
|
||||
original_url = (CFURLRef) CTFontCopyAttribute (ct_font, kCTFontURLAttribute);
|
||||
#endif
|
||||
|
||||
/* Create font copy with cascade list that has LastResort first; this speeds up CoreText
|
||||
* font fallback which we don't need anyway. */
|
||||
{
|
||||
CTFontDescriptorRef last_resort_font_desc = get_last_resort_font_desc ();
|
||||
CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0.0, nullptr, last_resort_font_desc);
|
||||
CFRelease (last_resort_font_desc);
|
||||
if (new_ct_font)
|
||||
{
|
||||
/* The CTFontCreateCopyWithAttributes call fails to stay on the same font
|
||||
* when reconfiguring the cascade list and may switch to a different font
|
||||
* when there are fonts that go by the same name, since the descriptor is
|
||||
* just name and size.
|
||||
*
|
||||
* Avoid reconfiguring the cascade lists if the new font is outside the
|
||||
* system locations that we cannot access from the sandboxed renderer
|
||||
* process in Blink. This can be detected by the new file URL location
|
||||
* that the newly found font points to. */
|
||||
CFURLRef new_url = nullptr;
|
||||
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
|
||||
atsFont = CTFontGetPlatformFont (new_ct_font, NULL);
|
||||
status = ATSFontGetFileReference (atsFont, &fsref);
|
||||
if (status == noErr)
|
||||
new_url = CFURLCreateFromFSRef (NULL, &fsref);
|
||||
#else
|
||||
new_url = (CFURLRef) CTFontCopyAttribute (new_ct_font, kCTFontURLAttribute);
|
||||
#endif
|
||||
// Keep reconfigured font if URL cannot be retrieved (seems to be the case
|
||||
// on Mac OS 10.12 Sierra), speculative fix for crbug.com/625606
|
||||
if (!original_url || !new_url || CFEqual (original_url, new_url)) {
|
||||
CFRelease (ct_font);
|
||||
ct_font = new_ct_font;
|
||||
} else {
|
||||
CFRelease (new_ct_font);
|
||||
DEBUG_MSG (CORETEXT, ct_font, "Discarding reconfigured CTFont, location changed.");
|
||||
}
|
||||
if (new_url)
|
||||
CFRelease (new_url);
|
||||
}
|
||||
else
|
||||
DEBUG_MSG (CORETEXT, ct_font, "Font copy with empty cascade list failed");
|
||||
}
|
||||
|
||||
if (original_url)
|
||||
CFRelease (original_url);
|
||||
return ct_font;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_coretext_face_create:
|
||||
* @cg_font: The CGFontRef to work upon
|
||||
*
|
||||
* Creates an #hb_face_t face object from the specified
|
||||
* CGFontRef.
|
||||
*
|
||||
* Return value: (transfer full): The new face object
|
||||
*
|
||||
* Since: 0.9.10
|
||||
*/
|
||||
hb_face_t *
|
||||
hb_coretext_face_create (CGFontRef cg_font)
|
||||
{
|
||||
hb_face_t *face = hb_face_create_for_tables (_hb_cg_reference_table, CGFontRetain (cg_font), _hb_cg_font_release);
|
||||
hb_face_set_get_table_tags_func (face, _hb_cg_get_table_tags, cg_font, nullptr);
|
||||
return face;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_coretext_face_create_from_file_or_fail:
|
||||
* @file_name: A font filename
|
||||
* @index: The index of the face within the file
|
||||
*
|
||||
* Creates an #hb_face_t face object from the specified
|
||||
* font file and face index.
|
||||
*
|
||||
* This is similar in functionality to hb_face_create_from_file_or_fail(),
|
||||
* but uses the CoreText library for loading the font file.
|
||||
*
|
||||
* Return value: (transfer full): The new face object, or `NULL` if
|
||||
* no face is found at the specified index or the file cannot be read.
|
||||
*
|
||||
* Since: 10.1.0
|
||||
*/
|
||||
hb_face_t *
|
||||
hb_coretext_face_create_from_file_or_fail (const char *file_name,
|
||||
unsigned int index)
|
||||
{
|
||||
auto url = CFURLCreateFromFileSystemRepresentation (nullptr,
|
||||
(const UInt8 *) file_name,
|
||||
strlen (file_name),
|
||||
false);
|
||||
if (unlikely (!url))
|
||||
return nullptr;
|
||||
|
||||
auto ct_font_desc_array = CTFontManagerCreateFontDescriptorsFromURL (url);
|
||||
if (unlikely (!ct_font_desc_array))
|
||||
{
|
||||
CFRelease (url);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unsigned ttc_index = index & 0xFFFF;
|
||||
unsigned named_instance_index = index >> 16;
|
||||
|
||||
if (ttc_index != 0)
|
||||
{
|
||||
DEBUG_MSG (CORETEXT, nullptr, "TTC index %u not supported", ttc_index);
|
||||
return nullptr; // CoreText does not support TTCs
|
||||
}
|
||||
|
||||
auto cg_font = create_cg_font (ct_font_desc_array, named_instance_index);
|
||||
CFRelease (url);
|
||||
|
||||
hb_face_t *face = hb_coretext_face_create (cg_font);
|
||||
CFRelease (cg_font);
|
||||
if (unlikely (hb_face_is_immutable (face)))
|
||||
return nullptr;
|
||||
|
||||
hb_face_set_index (face, index);
|
||||
|
||||
return face;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_coretext_face_create_from_blob_or_fail:
|
||||
* @blob: A blob containing the font data
|
||||
* @index: The index of the face within the blob
|
||||
*
|
||||
* Creates an #hb_face_t face object from the specified
|
||||
* blob and face index.
|
||||
*
|
||||
* This is similar in functionality to hb_face_create_from_blob_or_fail(),
|
||||
* but uses the CoreText library for loading the font data.
|
||||
*
|
||||
* Return value: (transfer full): The new face object, or `NULL` if
|
||||
* no face is found at the specified index or the blob cannot be read.
|
||||
*
|
||||
* Since: 11.0.0
|
||||
*/
|
||||
hb_face_t *
|
||||
hb_coretext_face_create_from_blob_or_fail (hb_blob_t *blob,
|
||||
unsigned int index)
|
||||
{
|
||||
auto cg_font = create_cg_font (blob, index);
|
||||
if (unlikely (!cg_font))
|
||||
return nullptr;
|
||||
|
||||
hb_face_t *face = hb_coretext_face_create (cg_font);
|
||||
CFRelease (cg_font);
|
||||
if (unlikely (hb_face_is_immutable (face)))
|
||||
return nullptr;
|
||||
|
||||
hb_face_set_index (face, index);
|
||||
|
||||
return face;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_coretext_face_get_cg_font:
|
||||
* @face: The #hb_face_t to work upon
|
||||
*
|
||||
* Fetches the CGFontRef associated with an #hb_face_t
|
||||
* face object
|
||||
*
|
||||
* Return value: the CGFontRef found
|
||||
*
|
||||
* Since: 0.9.10
|
||||
*/
|
||||
CGFontRef
|
||||
hb_coretext_face_get_cg_font (hb_face_t *face)
|
||||
{
|
||||
return (CGFontRef) (const void *) face->data.coretext;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_coretext_font_create:
|
||||
* @ct_font: The CTFontRef to work upon
|
||||
*
|
||||
* Creates an #hb_font_t font object from the specified
|
||||
* CTFontRef.
|
||||
*
|
||||
* The created font uses the default font functions implemented
|
||||
* natively by HarfBuzz. If you want to use the CoreText font functions
|
||||
* instead (rarely needed), you can do so by calling
|
||||
* by hb_coretext_font_set_funcs().
|
||||
*
|
||||
* Return value: (transfer full): The new font object
|
||||
*
|
||||
* Since: 1.7.2
|
||||
**/
|
||||
hb_font_t *
|
||||
hb_coretext_font_create (CTFontRef ct_font)
|
||||
{
|
||||
CGFontRef cg_font = CTFontCopyGraphicsFont (ct_font, nullptr);
|
||||
hb_face_t *face = hb_coretext_face_create (cg_font);
|
||||
CFRelease (cg_font);
|
||||
hb_font_t *font = hb_font_create (face);
|
||||
hb_face_destroy (face);
|
||||
|
||||
if (unlikely (hb_object_is_immutable (font)))
|
||||
return font;
|
||||
|
||||
hb_font_set_ptem (font, CTFontGetSize (ct_font));
|
||||
|
||||
/* Copy font variations */
|
||||
CFDictionaryRef variations = CTFontCopyVariation (ct_font);
|
||||
if (variations)
|
||||
{
|
||||
hb_vector_t<hb_variation_t> vars;
|
||||
hb_vector_t<CFTypeRef> keys;
|
||||
hb_vector_t<CFTypeRef> values;
|
||||
|
||||
CFIndex count = CFDictionaryGetCount (variations);
|
||||
if (unlikely (!vars.alloc_exact (count) || !keys.resize_exact (count) || !values.resize_exact (count)))
|
||||
goto done;
|
||||
|
||||
// Fetch them one by one and collect in a vector of our own.
|
||||
CFDictionaryGetKeysAndValues (variations, keys.arrayZ, values.arrayZ);
|
||||
for (CFIndex i = 0; i < count; i++)
|
||||
{
|
||||
int tag;
|
||||
float value;
|
||||
CFNumberGetValue ((CFNumberRef) keys.arrayZ[i], kCFNumberIntType, &tag);
|
||||
CFNumberGetValue ((CFNumberRef) values.arrayZ[i], kCFNumberFloatType, &value);
|
||||
|
||||
hb_variation_t var = {tag, value};
|
||||
vars.push (var);
|
||||
}
|
||||
hb_font_set_variations (font, vars.arrayZ, vars.length);
|
||||
|
||||
done:
|
||||
CFRelease (variations);
|
||||
}
|
||||
|
||||
/* Let there be dragons here... */
|
||||
font->data.coretext.cmpexch (nullptr, (hb_coretext_font_data_t *) CFRetain (ct_font));
|
||||
|
||||
// https://github.com/harfbuzz/harfbuzz/pull/4895#issuecomment-2408471254
|
||||
//hb_coretext_font_set_funcs (font);
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_coretext_font_get_ct_font:
|
||||
* @font: #hb_font_t to work upon
|
||||
*
|
||||
* Fetches the CTFontRef associated with the specified
|
||||
* #hb_font_t font object.
|
||||
*
|
||||
* Return value: the CTFontRef found
|
||||
*
|
||||
* Since: 0.9.10
|
||||
*/
|
||||
CTFontRef
|
||||
hb_coretext_font_get_ct_font (hb_font_t *font)
|
||||
{
|
||||
return (CTFontRef) (const void *) font->data.coretext;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -84,6 +84,10 @@ HB_EXTERN hb_face_t *
|
|||
hb_coretext_face_create_from_file_or_fail (const char *file_name,
|
||||
unsigned int index);
|
||||
|
||||
HB_EXTERN hb_face_t *
|
||||
hb_coretext_face_create_from_blob_or_fail (hb_blob_t *blob,
|
||||
unsigned int index);
|
||||
|
||||
HB_EXTERN hb_font_t *
|
||||
hb_coretext_font_create (CTFontRef ct_font);
|
||||
|
||||
|
|
53
src/hb-coretext.hh
Normal file
53
src/hb-coretext.hh
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright © 2012,2013 Mozilla Foundation.
|
||||
* Copyright © 2012,2013 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Mozilla Author(s): Jonathan Kew
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HB_CORETEXT_HH
|
||||
#define HB_CORETEXT_HH
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#include "hb-coretext.h"
|
||||
|
||||
#include "hb-aat-layout.hh"
|
||||
|
||||
|
||||
HB_INTERNAL CGFontRef
|
||||
create_cg_font (CFArrayRef ct_font_desc_array, unsigned int index);
|
||||
|
||||
HB_INTERNAL CGFontRef
|
||||
create_cg_font (hb_blob_t *blob, unsigned int index);
|
||||
|
||||
HB_INTERNAL CGFontRef
|
||||
create_cg_font (hb_face_t *face);
|
||||
|
||||
HB_INTERNAL CTFontRef
|
||||
create_ct_font (CGFontRef cg_font, CGFloat font_size);
|
||||
|
||||
|
||||
#endif /* HB_CORETEXT_HH */
|
|
@ -49,15 +49,15 @@ struct hb_options_t
|
|||
};
|
||||
|
||||
union hb_options_union_t {
|
||||
int i;
|
||||
unsigned i;
|
||||
hb_options_t opts;
|
||||
};
|
||||
static_assert ((sizeof (hb_atomic_int_t) >= sizeof (hb_options_union_t)), "");
|
||||
static_assert ((sizeof (hb_atomic_t<unsigned>) >= sizeof (hb_options_union_t)), "");
|
||||
|
||||
HB_INTERNAL void
|
||||
_hb_options_init ();
|
||||
|
||||
extern HB_INTERNAL hb_atomic_int_t _hb_options;
|
||||
extern HB_INTERNAL hb_atomic_t<unsigned> _hb_options;
|
||||
|
||||
static inline hb_options_t
|
||||
hb_options ()
|
||||
|
|
|
@ -38,11 +38,11 @@
|
|||
* For Floyd's tortoise and hare algorithm, see:
|
||||
* https://en.wikipedia.org/wiki/Cycle_detection#Floyd's_tortoise_and_hare
|
||||
*
|
||||
* Like Floyd's algorithm, hb_decycler_t is O(n) in the number of nodes
|
||||
* in the graph. Unlike Floyd's algorithm, hb_decycler_t is designed
|
||||
* to be used in a DFS traversal, where the graph is not a simple
|
||||
* linked list, but a tree with cycles. Like Floyd's algorithm, it is
|
||||
* constant-memory (just two pointers).
|
||||
* hb_decycler_t is O(n) in the number of nodes in the DFS traversal
|
||||
* if there are no cycles. Unlike Floyd's algorithm, hb_decycler_t
|
||||
* can be used in a DFS traversal, where the graph is not a simple
|
||||
* linked list, but a tree with possible cycles. Like Floyd's algorithm,
|
||||
* it is constant-memory (~three pointers).
|
||||
*
|
||||
* The decycler works by creating an implicit linked-list on the stack,
|
||||
* of the path from the root to the current node, and apply Floyd's
|
||||
|
@ -89,7 +89,7 @@ struct hb_decycler_t
|
|||
friend struct hb_decycler_node_t;
|
||||
|
||||
private:
|
||||
bool tortoise_asleep = true;
|
||||
bool tortoise_awake = false;
|
||||
hb_decycler_node_t *tortoise = nullptr;
|
||||
hb_decycler_node_t *hare = nullptr;
|
||||
};
|
||||
|
@ -100,15 +100,18 @@ struct hb_decycler_node_t
|
|||
{
|
||||
u.decycler = &decycler;
|
||||
|
||||
decycler.tortoise_asleep = !decycler.tortoise_asleep;
|
||||
decycler.tortoise_awake = !decycler.tortoise_awake;
|
||||
|
||||
if (!decycler.tortoise)
|
||||
{
|
||||
// First node.
|
||||
assert (decycler.tortoise_awake);
|
||||
assert (!decycler.hare);
|
||||
decycler.tortoise = decycler.hare = this;
|
||||
return;
|
||||
}
|
||||
if (!decycler.tortoise_asleep)
|
||||
|
||||
if (decycler.tortoise_awake)
|
||||
decycler.tortoise = decycler.tortoise->u.next; // Time to move.
|
||||
|
||||
this->prev = decycler.hare;
|
||||
|
@ -128,10 +131,10 @@ struct hb_decycler_node_t
|
|||
prev->u.decycler = &decycler;
|
||||
|
||||
assert (decycler.tortoise);
|
||||
if (!decycler.tortoise_asleep)
|
||||
if (decycler.tortoise_awake)
|
||||
decycler.tortoise = decycler.tortoise->prev;
|
||||
|
||||
decycler.tortoise_asleep = !decycler.tortoise_asleep;
|
||||
decycler.tortoise_awake = !decycler.tortoise_awake;
|
||||
}
|
||||
|
||||
bool visit (uintptr_t value_)
|
||||
|
|
388
src/hb-directwrite-font.cc
Normal file
388
src/hb-directwrite-font.cc
Normal file
|
@ -0,0 +1,388 @@
|
|||
/*
|
||||
* Copyright © 2025 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#ifdef HAVE_DIRECTWRITE
|
||||
|
||||
#include "hb-directwrite.h"
|
||||
|
||||
#include <d2d1.h>
|
||||
|
||||
#include "hb-draw.hh"
|
||||
#include "hb-font.hh"
|
||||
#include "hb-machinery.hh"
|
||||
|
||||
#define MAX_GLYPHS 256u
|
||||
|
||||
static unsigned int
|
||||
hb_directwrite_get_nominal_glyphs (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
unsigned int count,
|
||||
const hb_codepoint_t *first_unicode,
|
||||
unsigned int unicode_stride,
|
||||
hb_codepoint_t *first_glyph,
|
||||
unsigned int glyph_stride,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
|
||||
|
||||
for (unsigned i = 0; i < count;)
|
||||
{
|
||||
UINT32 unicodes[MAX_GLYPHS];
|
||||
UINT16 gids[MAX_GLYPHS];
|
||||
|
||||
unsigned n = hb_min (MAX_GLYPHS, count - i);
|
||||
|
||||
for (unsigned j = 0; j < n; j++)
|
||||
{
|
||||
unicodes[j] = *first_unicode;
|
||||
first_unicode = &StructAtOffset<const hb_codepoint_t> (first_unicode, unicode_stride);
|
||||
}
|
||||
|
||||
if (!SUCCEEDED (dw_face->GetGlyphIndices (unicodes, n, gids)))
|
||||
return i;
|
||||
|
||||
for (unsigned j = 0; j < n; j++)
|
||||
{
|
||||
if (!gids[j])
|
||||
return i + j;
|
||||
*first_glyph = gids[j];
|
||||
first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
|
||||
}
|
||||
|
||||
i += n;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
hb_directwrite_get_font_h_extents (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_font_extents_t *metrics,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
|
||||
|
||||
DWRITE_FONT_METRICS dw_metrics;
|
||||
dw_face->GetMetrics (&dw_metrics);
|
||||
|
||||
metrics->ascender = font->em_scale_y (dw_metrics.ascent);
|
||||
metrics->descender = -font->em_scale_y (dw_metrics.descent);
|
||||
metrics->line_gap = font->em_scale_y (dw_metrics.lineGap);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
hb_directwrite_get_glyph_h_advances (hb_font_t* font,
|
||||
void* font_data HB_UNUSED,
|
||||
unsigned count,
|
||||
const hb_codepoint_t *first_glyph,
|
||||
unsigned glyph_stride,
|
||||
hb_position_t *first_advance,
|
||||
unsigned advance_stride,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
|
||||
|
||||
IDWriteFontFace1 *dw_face1 = nullptr;
|
||||
dw_face->QueryInterface (__uuidof(IDWriteFontFace1), (void**)&dw_face1);
|
||||
assert (dw_face1);
|
||||
|
||||
for (unsigned i = 0; i < count;)
|
||||
{
|
||||
UINT16 gids[MAX_GLYPHS];
|
||||
INT32 advances[MAX_GLYPHS];
|
||||
|
||||
unsigned n = hb_min (MAX_GLYPHS, count - i);
|
||||
|
||||
for (unsigned j = 0; j < n; j++)
|
||||
{
|
||||
gids[j] = *first_glyph;
|
||||
advances[j] = 0;
|
||||
first_glyph = &StructAtOffset<const hb_codepoint_t> (first_glyph, glyph_stride);
|
||||
}
|
||||
dw_face1->GetDesignGlyphAdvances (n, gids, advances, false);
|
||||
for (unsigned j = 0; j < n; j++)
|
||||
{
|
||||
*first_advance = font->em_scale_x (advances[j]);
|
||||
first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
|
||||
}
|
||||
|
||||
i += n;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef HB_NO_VERTICAL
|
||||
|
||||
static void
|
||||
hb_directwrite_get_glyph_v_advances (hb_font_t* font,
|
||||
void* font_data HB_UNUSED,
|
||||
unsigned count,
|
||||
const hb_codepoint_t *first_glyph,
|
||||
unsigned glyph_stride,
|
||||
hb_position_t *first_advance,
|
||||
unsigned advance_stride,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
|
||||
|
||||
IDWriteFontFace1 *dw_face1 = nullptr;
|
||||
dw_face->QueryInterface (__uuidof(IDWriteFontFace1), (void**)&dw_face1);
|
||||
assert (dw_face1);
|
||||
|
||||
for (unsigned i = 0; i < count;)
|
||||
{
|
||||
UINT16 gids[MAX_GLYPHS];
|
||||
INT32 advances[MAX_GLYPHS];
|
||||
|
||||
unsigned n = hb_min (MAX_GLYPHS, count - i);
|
||||
|
||||
for (unsigned j = 0; j < n; j++)
|
||||
{
|
||||
gids[j] = *first_glyph;
|
||||
advances[j] = 0;
|
||||
first_glyph = &StructAtOffset<const hb_codepoint_t> (first_glyph, glyph_stride);
|
||||
}
|
||||
dw_face1->GetDesignGlyphAdvances (n, gids, advances, true);
|
||||
for (unsigned j = 0; j < n; j++)
|
||||
{
|
||||
*first_advance = -font->em_scale_y (advances[j]);
|
||||
first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
|
||||
}
|
||||
|
||||
i += n;
|
||||
}
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
hb_directwrite_get_glyph_v_origin (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t glyph,
|
||||
hb_position_t *x,
|
||||
hb_position_t *y,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
|
||||
|
||||
UINT16 gid = glyph;
|
||||
DWRITE_GLYPH_METRICS metrics;
|
||||
|
||||
if (FAILED (dw_face->GetDesignGlyphMetrics (&gid, 1, &metrics)))
|
||||
return false;
|
||||
|
||||
*x = font->em_scale_x (metrics.advanceWidth / 2);
|
||||
*y = font->em_scale_y (metrics.verticalOriginY); // Untested
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static hb_bool_t
|
||||
hb_directwrite_get_glyph_extents (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t glyph,
|
||||
hb_glyph_extents_t *extents,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
|
||||
|
||||
UINT16 gid = glyph;
|
||||
DWRITE_GLYPH_METRICS metrics;
|
||||
|
||||
if (FAILED (dw_face->GetDesignGlyphMetrics (&gid, 1, &metrics)))
|
||||
return false;
|
||||
|
||||
extents->x_bearing = font->em_scale_x (metrics.leftSideBearing);
|
||||
extents->y_bearing = font->em_scale_y (metrics.verticalOriginY - metrics.topSideBearing);
|
||||
extents->width = font->em_scale_x (metrics.advanceWidth - metrics.rightSideBearing) - extents->x_bearing;
|
||||
extents->height = font->em_scale_y (metrics.verticalOriginY - metrics.advanceHeight + metrics.bottomSideBearing) - extents->y_bearing; // Magic
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#ifndef HB_NO_DRAW
|
||||
|
||||
class GeometrySink : public IDWriteGeometrySink
|
||||
{
|
||||
hb_font_t *font;
|
||||
hb_draw_session_t drawing;
|
||||
|
||||
public:
|
||||
GeometrySink(hb_font_t *font,
|
||||
hb_draw_funcs_t *draw_funcs,
|
||||
void *draw_data)
|
||||
: font (font), drawing ({draw_funcs, draw_data, font->slant}) {}
|
||||
|
||||
virtual ~GeometrySink() {}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Close() override { return S_OK; }
|
||||
void STDMETHODCALLTYPE SetFillMode(D2D1_FILL_MODE) override {}
|
||||
void STDMETHODCALLTYPE SetSegmentFlags(D2D1_PATH_SEGMENT) override {}
|
||||
|
||||
IFACEMETHOD(QueryInterface)(REFIID, void **) override { return E_NOINTERFACE; }
|
||||
IFACEMETHOD_(ULONG, AddRef)() override { return 1; }
|
||||
IFACEMETHOD_(ULONG, Release)() override { return 1; }
|
||||
|
||||
void STDMETHODCALLTYPE BeginFigure(D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN) override
|
||||
{
|
||||
drawing.move_to (font->em_scalef_x (startPoint.x), -font->em_scalef_y (startPoint.y));
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE AddBeziers(const D2D1_BEZIER_SEGMENT *beziers, UINT beziersCount) override
|
||||
{
|
||||
for (unsigned i = 0; i < beziersCount; ++i)
|
||||
drawing.cubic_to (font->em_scalef_x (beziers[i].point1.x), -font->em_scalef_y (beziers[i].point1.y),
|
||||
font->em_scalef_x (beziers[i].point2.x), -font->em_scalef_y (beziers[i].point2.y),
|
||||
font->em_scalef_x (beziers[i].point3.x), -font->em_scalef_y (beziers[i].point3.y));
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE AddLines(const D2D1_POINT_2F *points, UINT pointsCount) override
|
||||
{
|
||||
for (unsigned i = 0; i < pointsCount; ++i)
|
||||
drawing.line_to (font->em_scalef_x (points[i].x), -font->em_scalef_y (points[i].y));
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE EndFigure(D2D1_FIGURE_END) override
|
||||
{
|
||||
drawing.close_path ();
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
hb_directwrite_draw_glyph (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t glyph,
|
||||
hb_draw_funcs_t *draw_funcs, void *draw_data,
|
||||
void *user_data)
|
||||
{
|
||||
IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
|
||||
|
||||
GeometrySink sink (font, draw_funcs, draw_data);
|
||||
UINT16 gid = static_cast<UINT16>(glyph);
|
||||
unsigned upem = font->face->get_upem();
|
||||
|
||||
(void) dw_face->GetGlyphRunOutline (upem,
|
||||
&gid, nullptr, nullptr,
|
||||
1,
|
||||
false, false,
|
||||
&sink);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static inline void free_static_directwrite_funcs ();
|
||||
|
||||
static struct hb_directwrite_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_directwrite_font_funcs_lazy_loader_t>
|
||||
{
|
||||
static hb_font_funcs_t *create ()
|
||||
{
|
||||
hb_font_funcs_t *funcs = hb_font_funcs_create ();
|
||||
|
||||
hb_font_funcs_set_nominal_glyphs_func (funcs, hb_directwrite_get_nominal_glyphs, nullptr, nullptr);
|
||||
//hb_font_funcs_set_variation_glyph_func (funcs, hb_directwrite_get_variation_glyph, nullptr, nullptr);
|
||||
|
||||
hb_font_funcs_set_font_h_extents_func (funcs, hb_directwrite_get_font_h_extents, nullptr, nullptr);
|
||||
hb_font_funcs_set_glyph_h_advances_func (funcs, hb_directwrite_get_glyph_h_advances, nullptr, nullptr);
|
||||
|
||||
#ifndef HB_NO_VERTICAL
|
||||
hb_font_funcs_set_glyph_v_advances_func (funcs, hb_directwrite_get_glyph_v_advances, nullptr, nullptr);
|
||||
hb_font_funcs_set_glyph_v_origin_func (funcs, hb_directwrite_get_glyph_v_origin, nullptr, nullptr);
|
||||
#endif
|
||||
|
||||
#ifndef HB_NO_DRAW
|
||||
hb_font_funcs_set_draw_glyph_func (funcs, hb_directwrite_draw_glyph, nullptr, nullptr);
|
||||
#endif
|
||||
|
||||
hb_font_funcs_set_glyph_extents_func (funcs, hb_directwrite_get_glyph_extents, nullptr, nullptr);
|
||||
|
||||
#ifndef HB_NO_OT_FONT_GLYPH_NAMES
|
||||
//hb_font_funcs_set_glyph_name_func (funcs, hb_directwrite_get_glyph_name, nullptr, nullptr);
|
||||
//hb_font_funcs_set_glyph_from_name_func (funcs, hb_directwrite_get_glyph_from_name, nullptr, nullptr);
|
||||
#endif
|
||||
|
||||
hb_font_funcs_make_immutable (funcs);
|
||||
|
||||
hb_atexit (free_static_directwrite_funcs);
|
||||
|
||||
return funcs;
|
||||
}
|
||||
} static_directwrite_funcs;
|
||||
|
||||
static inline
|
||||
void free_static_directwrite_funcs ()
|
||||
{
|
||||
static_directwrite_funcs.free_instance ();
|
||||
}
|
||||
|
||||
static hb_font_funcs_t *
|
||||
_hb_directwrite_get_font_funcs ()
|
||||
{
|
||||
return static_directwrite_funcs.get_unconst ();
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_directwrite_font_set_funcs:
|
||||
* @font: #hb_font_t to work upon
|
||||
*
|
||||
* Configures the font-functions structure of the specified
|
||||
* #hb_font_t font object to use DirectWrite font functions.
|
||||
*
|
||||
* In particular, you can use this function to configure an
|
||||
* existing #hb_face_t face object for use with DirectWrite font
|
||||
* functions even if that #hb_face_t face object was initially
|
||||
* created with hb_face_create(), and therefore was not
|
||||
* initially configured to use DirectWrite font functions.
|
||||
*
|
||||
* <note>Note: Internally, this function creates a DirectWrite font.
|
||||
* </note>
|
||||
*
|
||||
* Since: 11.0.0
|
||||
**/
|
||||
void
|
||||
hb_directwrite_font_set_funcs (hb_font_t *font)
|
||||
{
|
||||
IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
|
||||
if (unlikely (!dw_face))
|
||||
{
|
||||
hb_font_set_funcs (font,
|
||||
hb_font_funcs_get_empty (),
|
||||
nullptr, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
dw_face->AddRef ();
|
||||
hb_font_set_funcs (font,
|
||||
_hb_directwrite_get_font_funcs (),
|
||||
nullptr, nullptr);
|
||||
}
|
||||
|
||||
#undef MAX_GLYPHS
|
||||
|
||||
#endif
|
656
src/hb-directwrite-shape.cc
Normal file
656
src/hb-directwrite-shape.cc
Normal file
|
@ -0,0 +1,656 @@
|
|||
/*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#ifdef HAVE_DIRECTWRITE
|
||||
|
||||
#include "hb-shaper-impl.hh"
|
||||
|
||||
#include "hb-directwrite.hh"
|
||||
|
||||
#include "hb-ms-feature-ranges.hh"
|
||||
|
||||
|
||||
/*
|
||||
* shaper face data
|
||||
*/
|
||||
|
||||
hb_directwrite_face_data_t *
|
||||
_hb_directwrite_shaper_face_data_create (hb_face_t *face)
|
||||
{
|
||||
hb_blob_t *blob = hb_face_reference_blob (face);
|
||||
|
||||
hb_directwrite_face_data_t *data = (hb_directwrite_face_data_t *) dw_face_create (blob, face->index);
|
||||
|
||||
hb_blob_destroy (blob);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_directwrite_shaper_face_data_destroy (hb_directwrite_face_data_t *data)
|
||||
{
|
||||
((IDWriteFontFace *) data)->Release ();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* shaper font data
|
||||
*/
|
||||
|
||||
struct hb_directwrite_font_data_t {};
|
||||
|
||||
hb_directwrite_font_data_t *
|
||||
_hb_directwrite_shaper_font_data_create (hb_font_t *font)
|
||||
{
|
||||
IDWriteFontFace *fontFace = (IDWriteFontFace *) (const void *) font->face->data.directwrite;
|
||||
|
||||
/*
|
||||
* Set up variations.
|
||||
*/
|
||||
IDWriteFontFace5 *fontFaceVariations = nullptr;
|
||||
{
|
||||
IDWriteFontFace5 *fontFace5;
|
||||
if (SUCCEEDED (fontFace->QueryInterface (__uuidof (IDWriteFontFace5), (void **) &fontFace5)))
|
||||
{
|
||||
IDWriteFontResource *fontResource;
|
||||
if (SUCCEEDED (fontFace5->GetFontResource (&fontResource)))
|
||||
{
|
||||
hb_vector_t<DWRITE_FONT_AXIS_VALUE> axis_values;
|
||||
if (likely (axis_values.resize_exact (font->num_coords)))
|
||||
{
|
||||
for (unsigned int i = 0; i < font->num_coords; i++)
|
||||
{
|
||||
hb_ot_var_axis_info_t info;
|
||||
unsigned int c = 1;
|
||||
hb_ot_var_get_axis_infos (font->face, i, &c, &info);
|
||||
axis_values[i].axisTag = (DWRITE_FONT_AXIS_TAG) hb_uint32_swap (info.tag);
|
||||
axis_values[i].value = i < font->num_coords ?
|
||||
hb_clamp (font->design_coords[i], info.min_value, info.max_value) :
|
||||
info.default_value;
|
||||
}
|
||||
|
||||
fontResource->CreateFontFace (DWRITE_FONT_SIMULATIONS::DWRITE_FONT_SIMULATIONS_NONE,
|
||||
axis_values.arrayZ, axis_values.length, &fontFaceVariations);
|
||||
}
|
||||
fontResource->Release ();
|
||||
}
|
||||
fontFace5->Release ();
|
||||
}
|
||||
}
|
||||
|
||||
return (hb_directwrite_font_data_t *) fontFaceVariations;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_directwrite_shaper_font_data_destroy (hb_directwrite_font_data_t *data)
|
||||
{
|
||||
((IDWriteFontFace *) (const void *) data)->Release ();
|
||||
}
|
||||
|
||||
|
||||
// Most of TextAnalysis is originally written by Bas Schouten for Mozilla project
|
||||
// but now is relicensed to MIT for HarfBuzz use
|
||||
class TextAnalysis : public IDWriteTextAnalysisSource, public IDWriteTextAnalysisSink
|
||||
{
|
||||
private:
|
||||
hb_reference_count_t mRefCount;
|
||||
public:
|
||||
IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject)
|
||||
{ return S_OK; }
|
||||
IFACEMETHOD_ (ULONG, AddRef) ()
|
||||
{
|
||||
return mRefCount.inc () + 1;
|
||||
}
|
||||
IFACEMETHOD_ (ULONG, Release) ()
|
||||
{
|
||||
signed refCount = mRefCount.dec () - 1;
|
||||
assert (refCount >= 0);
|
||||
if (refCount)
|
||||
return refCount;
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// A single contiguous run of characters containing the same analysis
|
||||
// results.
|
||||
struct Run
|
||||
{
|
||||
uint32_t mTextStart; // starting text position of this run
|
||||
uint32_t mTextLength; // number of contiguous code units covered
|
||||
uint32_t mGlyphStart; // starting glyph in the glyphs array
|
||||
uint32_t mGlyphCount; // number of glyphs associated with this run
|
||||
// text
|
||||
DWRITE_SCRIPT_ANALYSIS mScript;
|
||||
uint8_t mBidiLevel;
|
||||
bool mIsSideways;
|
||||
|
||||
bool ContainsTextPosition (uint32_t aTextPosition) const
|
||||
{
|
||||
return aTextPosition >= mTextStart &&
|
||||
aTextPosition < mTextStart + mTextLength;
|
||||
}
|
||||
|
||||
Run *nextRun;
|
||||
};
|
||||
|
||||
public:
|
||||
TextAnalysis (const wchar_t* text, uint32_t textLength,
|
||||
const wchar_t* localeName, DWRITE_READING_DIRECTION readingDirection)
|
||||
: mTextLength (textLength), mText (text), mLocaleName (localeName),
|
||||
mReadingDirection (readingDirection), mCurrentRun (nullptr)
|
||||
{
|
||||
mRefCount.init ();
|
||||
}
|
||||
virtual ~TextAnalysis ()
|
||||
{
|
||||
// delete runs, except mRunHead which is part of the TextAnalysis object
|
||||
for (Run *run = mRunHead.nextRun; run;)
|
||||
{
|
||||
Run *origRun = run;
|
||||
run = run->nextRun;
|
||||
delete origRun;
|
||||
}
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
GenerateResults (IDWriteTextAnalyzer* textAnalyzer, Run **runHead)
|
||||
{
|
||||
// Analyzes the text using the script analyzer and returns
|
||||
// the result as a series of runs.
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
// Initially start out with one result that covers the entire range.
|
||||
// This result will be subdivided by the analysis processes.
|
||||
mRunHead.mTextStart = 0;
|
||||
mRunHead.mTextLength = mTextLength;
|
||||
mRunHead.mBidiLevel =
|
||||
(mReadingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
|
||||
mRunHead.nextRun = nullptr;
|
||||
mCurrentRun = &mRunHead;
|
||||
|
||||
// Call each of the analyzers in sequence, recording their results.
|
||||
if (SUCCEEDED (hr = textAnalyzer->AnalyzeScript (this, 0, mTextLength, this)))
|
||||
*runHead = &mRunHead;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
// IDWriteTextAnalysisSource implementation
|
||||
|
||||
IFACEMETHODIMP
|
||||
GetTextAtPosition (uint32_t textPosition,
|
||||
OUT wchar_t const** textString,
|
||||
OUT uint32_t* textLength)
|
||||
{
|
||||
if (textPosition >= mTextLength)
|
||||
{
|
||||
// No text at this position, valid query though.
|
||||
*textString = nullptr;
|
||||
*textLength = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*textString = mText + textPosition;
|
||||
*textLength = mTextLength - textPosition;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP
|
||||
GetTextBeforePosition (uint32_t textPosition,
|
||||
OUT wchar_t const** textString,
|
||||
OUT uint32_t* textLength)
|
||||
{
|
||||
if (textPosition == 0 || textPosition > mTextLength)
|
||||
{
|
||||
// Either there is no text before here (== 0), or this
|
||||
// is an invalid position. The query is considered valid though.
|
||||
*textString = nullptr;
|
||||
*textLength = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*textString = mText;
|
||||
*textLength = textPosition;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_ (DWRITE_READING_DIRECTION)
|
||||
GetParagraphReadingDirection () { return mReadingDirection; }
|
||||
|
||||
IFACEMETHODIMP GetLocaleName (uint32_t textPosition, uint32_t* textLength,
|
||||
wchar_t const** localeName)
|
||||
{ return S_OK; }
|
||||
|
||||
IFACEMETHODIMP
|
||||
GetNumberSubstitution (uint32_t textPosition,
|
||||
OUT uint32_t* textLength,
|
||||
OUT IDWriteNumberSubstitution** numberSubstitution)
|
||||
{
|
||||
// We do not support number substitution.
|
||||
*numberSubstitution = nullptr;
|
||||
*textLength = mTextLength - textPosition;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// IDWriteTextAnalysisSink implementation
|
||||
|
||||
IFACEMETHODIMP
|
||||
SetScriptAnalysis (uint32_t textPosition, uint32_t textLength,
|
||||
DWRITE_SCRIPT_ANALYSIS const* scriptAnalysis)
|
||||
{
|
||||
SetCurrentRun (textPosition);
|
||||
SplitCurrentRun (textPosition);
|
||||
while (textLength > 0)
|
||||
{
|
||||
Run *run = FetchNextRun (&textLength);
|
||||
run->mScript = *scriptAnalysis;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP
|
||||
SetLineBreakpoints (uint32_t textPosition,
|
||||
uint32_t textLength,
|
||||
const DWRITE_LINE_BREAKPOINT* lineBreakpoints)
|
||||
{ return S_OK; }
|
||||
|
||||
IFACEMETHODIMP SetBidiLevel (uint32_t textPosition, uint32_t textLength,
|
||||
uint8_t explicitLevel, uint8_t resolvedLevel)
|
||||
{ return S_OK; }
|
||||
|
||||
IFACEMETHODIMP
|
||||
SetNumberSubstitution (uint32_t textPosition, uint32_t textLength,
|
||||
IDWriteNumberSubstitution* numberSubstitution)
|
||||
{ return S_OK; }
|
||||
|
||||
protected:
|
||||
Run *FetchNextRun (IN OUT uint32_t* textLength)
|
||||
{
|
||||
// Used by the sink setters, this returns a reference to the next run.
|
||||
// Position and length are adjusted to now point after the current run
|
||||
// being returned.
|
||||
|
||||
Run *origRun = mCurrentRun;
|
||||
// Split the tail if needed (the length remaining is less than the
|
||||
// current run's size).
|
||||
if (*textLength < mCurrentRun->mTextLength)
|
||||
SplitCurrentRun (mCurrentRun->mTextStart + *textLength);
|
||||
else
|
||||
// Just advance the current run.
|
||||
mCurrentRun = mCurrentRun->nextRun;
|
||||
*textLength -= origRun->mTextLength;
|
||||
|
||||
// Return a reference to the run that was just current.
|
||||
return origRun;
|
||||
}
|
||||
|
||||
void SetCurrentRun (uint32_t textPosition)
|
||||
{
|
||||
// Move the current run to the given position.
|
||||
// Since the analyzers generally return results in a forward manner,
|
||||
// this will usually just return early. If not, find the
|
||||
// corresponding run for the text position.
|
||||
|
||||
if (mCurrentRun && mCurrentRun->ContainsTextPosition (textPosition))
|
||||
return;
|
||||
|
||||
for (Run *run = &mRunHead; run; run = run->nextRun)
|
||||
if (run->ContainsTextPosition (textPosition))
|
||||
{
|
||||
mCurrentRun = run;
|
||||
return;
|
||||
}
|
||||
assert (0); // We should always be able to find the text position in one of our runs
|
||||
}
|
||||
|
||||
void SplitCurrentRun (uint32_t splitPosition)
|
||||
{
|
||||
if (!mCurrentRun)
|
||||
{
|
||||
assert (0); // SplitCurrentRun called without current run
|
||||
// Shouldn't be calling this when no current run is set!
|
||||
return;
|
||||
}
|
||||
// Split the current run.
|
||||
if (splitPosition <= mCurrentRun->mTextStart)
|
||||
{
|
||||
// No need to split, already the start of a run
|
||||
// or before it. Usually the first.
|
||||
return;
|
||||
}
|
||||
Run *newRun = new Run;
|
||||
|
||||
*newRun = *mCurrentRun;
|
||||
|
||||
// Insert the new run in our linked list.
|
||||
newRun->nextRun = mCurrentRun->nextRun;
|
||||
mCurrentRun->nextRun = newRun;
|
||||
|
||||
// Adjust runs' text positions and lengths.
|
||||
uint32_t splitPoint = splitPosition - mCurrentRun->mTextStart;
|
||||
newRun->mTextStart += splitPoint;
|
||||
newRun->mTextLength -= splitPoint;
|
||||
mCurrentRun->mTextLength = splitPoint;
|
||||
mCurrentRun = newRun;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Input
|
||||
// (weak references are fine here, since this class is a transient
|
||||
// stack-based helper that doesn't need to copy data)
|
||||
uint32_t mTextLength;
|
||||
const wchar_t* mText;
|
||||
const wchar_t* mLocaleName;
|
||||
DWRITE_READING_DIRECTION mReadingDirection;
|
||||
|
||||
// Current processing state.
|
||||
Run *mCurrentRun;
|
||||
|
||||
// Output is a list of runs starting here
|
||||
Run mRunHead;
|
||||
};
|
||||
|
||||
/*
|
||||
* shaper
|
||||
*/
|
||||
|
||||
hb_bool_t
|
||||
_hb_directwrite_shape (hb_shape_plan_t *shape_plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer,
|
||||
const hb_feature_t *features,
|
||||
unsigned int num_features)
|
||||
{
|
||||
IDWriteFontFace *fontFace = (IDWriteFontFace *) (const void *) font->data.directwrite;
|
||||
auto *global = get_directwrite_global ();
|
||||
if (unlikely (!global))
|
||||
return false;
|
||||
IDWriteFactory *dwriteFactory = global->dwriteFactory;
|
||||
|
||||
IDWriteTextAnalyzer* analyzer;
|
||||
dwriteFactory->CreateTextAnalyzer (&analyzer);
|
||||
|
||||
unsigned int scratch_size;
|
||||
hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
|
||||
#define ALLOCATE_ARRAY(Type, name, len) \
|
||||
Type *name = (Type *) scratch; \
|
||||
do { \
|
||||
unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
|
||||
assert (_consumed <= scratch_size); \
|
||||
scratch += _consumed; \
|
||||
scratch_size -= _consumed; \
|
||||
} while (0)
|
||||
|
||||
#define utf16_index() var1.u32
|
||||
|
||||
ALLOCATE_ARRAY (wchar_t, textString, buffer->len * 2);
|
||||
|
||||
unsigned int chars_len = 0;
|
||||
for (unsigned int i = 0; i < buffer->len; i++)
|
||||
{
|
||||
hb_codepoint_t c = buffer->info[i].codepoint;
|
||||
buffer->info[i].utf16_index () = chars_len;
|
||||
if (likely (c <= 0xFFFFu))
|
||||
textString[chars_len++] = c;
|
||||
else if (unlikely (c > 0x10FFFFu))
|
||||
textString[chars_len++] = 0xFFFDu;
|
||||
else
|
||||
{
|
||||
textString[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
|
||||
textString[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1u << 10) - 1));
|
||||
}
|
||||
}
|
||||
|
||||
ALLOCATE_ARRAY (WORD, log_clusters, chars_len);
|
||||
/* Need log_clusters to assign features. */
|
||||
chars_len = 0;
|
||||
for (unsigned int i = 0; i < buffer->len; i++)
|
||||
{
|
||||
hb_codepoint_t c = buffer->info[i].codepoint;
|
||||
unsigned int cluster = buffer->info[i].cluster;
|
||||
log_clusters[chars_len++] = cluster;
|
||||
if (hb_in_range (c, 0x10000u, 0x10FFFFu))
|
||||
log_clusters[chars_len++] = cluster; /* Surrogates. */
|
||||
}
|
||||
|
||||
DWRITE_READING_DIRECTION readingDirection;
|
||||
readingDirection = buffer->props.direction ?
|
||||
DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
|
||||
DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
|
||||
|
||||
/*
|
||||
* There's an internal 16-bit limit on some things inside the analyzer,
|
||||
* but we never attempt to shape a word longer than 64K characters
|
||||
* in a single gfxShapedWord, so we cannot exceed that limit.
|
||||
*/
|
||||
uint32_t textLength = chars_len;
|
||||
|
||||
TextAnalysis analysis (textString, textLength, nullptr, readingDirection);
|
||||
TextAnalysis::Run *runHead;
|
||||
HRESULT hr;
|
||||
hr = analysis.GenerateResults (analyzer, &runHead);
|
||||
|
||||
#define FAIL(...) \
|
||||
HB_STMT_START { \
|
||||
DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \
|
||||
return false; \
|
||||
} HB_STMT_END
|
||||
|
||||
if (FAILED (hr))
|
||||
FAIL ("Analyzer failed to generate results.");
|
||||
|
||||
uint32_t maxGlyphCount = 3 * textLength / 2 + 16;
|
||||
uint32_t glyphCount;
|
||||
bool isRightToLeft = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
|
||||
|
||||
const wchar_t localeName[20] = {0};
|
||||
if (buffer->props.language)
|
||||
mbstowcs ((wchar_t*) localeName,
|
||||
hb_language_to_string (buffer->props.language), 20);
|
||||
|
||||
/*
|
||||
* Set up features.
|
||||
*/
|
||||
static_assert ((sizeof (DWRITE_TYPOGRAPHIC_FEATURES) == sizeof (hb_ms_features_t)), "");
|
||||
static_assert ((sizeof (DWRITE_FONT_FEATURE) == sizeof (hb_ms_feature_t)), "");
|
||||
hb_vector_t<hb_ms_features_t *> range_features;
|
||||
hb_vector_t<uint32_t> range_char_counts;
|
||||
|
||||
// https://github.com/harfbuzz/harfbuzz/pull/5114
|
||||
// The data allocated by these two vectors are used by the above two, so they
|
||||
// should remain alive as long as the above two are.
|
||||
hb_vector_t<hb_ms_feature_t> feature_records;
|
||||
hb_vector_t<hb_ms_range_record_t> range_records;
|
||||
if (num_features)
|
||||
{
|
||||
if (hb_ms_setup_features (features, num_features, feature_records, range_records))
|
||||
{
|
||||
hb_ms_make_feature_ranges (feature_records,
|
||||
range_records,
|
||||
0,
|
||||
chars_len,
|
||||
log_clusters,
|
||||
range_features,
|
||||
range_char_counts);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t* clusterMap;
|
||||
clusterMap = new uint16_t[textLength];
|
||||
DWRITE_SHAPING_TEXT_PROPERTIES* textProperties;
|
||||
textProperties = new DWRITE_SHAPING_TEXT_PROPERTIES[textLength];
|
||||
|
||||
retry_getglyphs:
|
||||
uint16_t* glyphIndices = new uint16_t[maxGlyphCount];
|
||||
DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties;
|
||||
glyphProperties = new DWRITE_SHAPING_GLYPH_PROPERTIES[maxGlyphCount];
|
||||
|
||||
hr = analyzer->GetGlyphs (textString,
|
||||
chars_len,
|
||||
fontFace,
|
||||
false,
|
||||
isRightToLeft,
|
||||
&runHead->mScript,
|
||||
localeName,
|
||||
nullptr,
|
||||
(const DWRITE_TYPOGRAPHIC_FEATURES**) range_features.arrayZ,
|
||||
range_char_counts.arrayZ,
|
||||
range_features.length,
|
||||
maxGlyphCount,
|
||||
clusterMap,
|
||||
textProperties,
|
||||
glyphIndices,
|
||||
glyphProperties,
|
||||
&glyphCount);
|
||||
|
||||
if (unlikely (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER)))
|
||||
{
|
||||
delete [] glyphIndices;
|
||||
delete [] glyphProperties;
|
||||
|
||||
maxGlyphCount *= 2;
|
||||
|
||||
goto retry_getglyphs;
|
||||
}
|
||||
if (FAILED (hr))
|
||||
FAIL ("Analyzer failed to get glyphs.");
|
||||
|
||||
float* glyphAdvances = new float[maxGlyphCount];
|
||||
DWRITE_GLYPH_OFFSET* glyphOffsets = new DWRITE_GLYPH_OFFSET[maxGlyphCount];
|
||||
|
||||
/* The -2 in the following is to compensate for possible
|
||||
* alignment needed after the WORD array. sizeof (WORD) == 2. */
|
||||
unsigned int glyphs_size = (scratch_size * sizeof (int) - 2)
|
||||
/ (sizeof (WORD) +
|
||||
sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES) +
|
||||
sizeof (int) +
|
||||
sizeof (DWRITE_GLYPH_OFFSET) +
|
||||
sizeof (uint32_t));
|
||||
ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size);
|
||||
|
||||
#undef ALLOCATE_ARRAY
|
||||
|
||||
unsigned fontEmSize = font->face->get_upem ();
|
||||
|
||||
float x_mult = font->x_multf;
|
||||
float y_mult = font->y_multf;
|
||||
|
||||
hr = analyzer->GetGlyphPlacements (textString,
|
||||
clusterMap,
|
||||
textProperties,
|
||||
chars_len,
|
||||
glyphIndices,
|
||||
glyphProperties,
|
||||
glyphCount,
|
||||
fontFace,
|
||||
fontEmSize,
|
||||
false,
|
||||
isRightToLeft,
|
||||
&runHead->mScript,
|
||||
localeName,
|
||||
(const DWRITE_TYPOGRAPHIC_FEATURES**) range_features.arrayZ,
|
||||
range_char_counts.arrayZ,
|
||||
range_features.length,
|
||||
glyphAdvances,
|
||||
glyphOffsets);
|
||||
|
||||
if (FAILED (hr))
|
||||
FAIL ("Analyzer failed to get glyph placements.");
|
||||
|
||||
/* Ok, we've got everything we need, now compose output buffer,
|
||||
* very, *very*, carefully! */
|
||||
|
||||
/* Calculate visual-clusters. That's what we ship. */
|
||||
for (unsigned int i = 0; i < glyphCount; i++)
|
||||
vis_clusters[i] = (uint32_t) -1;
|
||||
for (unsigned int i = 0; i < buffer->len; i++)
|
||||
{
|
||||
uint32_t *p =
|
||||
&vis_clusters[log_clusters[buffer->info[i].utf16_index ()]];
|
||||
*p = hb_min (*p, buffer->info[i].cluster);
|
||||
}
|
||||
for (unsigned int i = 1; i < glyphCount; i++)
|
||||
if (vis_clusters[i] == (uint32_t) -1)
|
||||
vis_clusters[i] = vis_clusters[i - 1];
|
||||
|
||||
#undef utf16_index
|
||||
|
||||
if (unlikely (!buffer->ensure (glyphCount)))
|
||||
FAIL ("Buffer in error");
|
||||
|
||||
#undef FAIL
|
||||
|
||||
/* Set glyph infos */
|
||||
buffer->len = 0;
|
||||
for (unsigned int i = 0; i < glyphCount; i++)
|
||||
{
|
||||
hb_glyph_info_t *info = &buffer->info[buffer->len++];
|
||||
|
||||
info->codepoint = glyphIndices[i];
|
||||
info->cluster = vis_clusters[i];
|
||||
|
||||
/* The rest is crap. Let's store position info there for now. */
|
||||
info->mask = glyphAdvances[i];
|
||||
info->var1.i32 = glyphOffsets[i].advanceOffset;
|
||||
info->var2.i32 = glyphOffsets[i].ascenderOffset;
|
||||
}
|
||||
|
||||
/* Set glyph positions */
|
||||
buffer->clear_positions ();
|
||||
for (unsigned int i = 0; i < glyphCount; i++)
|
||||
{
|
||||
hb_glyph_info_t *info = &buffer->info[i];
|
||||
hb_glyph_position_t *pos = &buffer->pos[i];
|
||||
|
||||
/* TODO vertical */
|
||||
pos->x_advance = round (x_mult * (int32_t) info->mask);
|
||||
pos->x_offset = round (x_mult * (isRightToLeft ? -info->var1.i32 : info->var1.i32));
|
||||
pos->y_offset = round (y_mult * info->var2.i32);
|
||||
}
|
||||
|
||||
if (isRightToLeft) hb_buffer_reverse (buffer);
|
||||
|
||||
buffer->clear_glyph_flags ();
|
||||
buffer->unsafe_to_break ();
|
||||
|
||||
delete [] clusterMap;
|
||||
delete [] glyphIndices;
|
||||
delete [] textProperties;
|
||||
delete [] glyphProperties;
|
||||
delete [] glyphAdvances;
|
||||
delete [] glyphOffsets;
|
||||
|
||||
/* Wow, done! */
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load diff
|
@ -27,20 +27,45 @@
|
|||
|
||||
#include "hb.h"
|
||||
|
||||
#include <dwrite_3.h>
|
||||
|
||||
HB_BEGIN_DECLS
|
||||
|
||||
HB_EXTERN hb_face_t *
|
||||
hb_directwrite_face_create (IDWriteFontFace *dw_face);
|
||||
|
||||
HB_EXTERN hb_face_t *
|
||||
hb_directwrite_face_create_from_file_or_fail (const char *file_name,
|
||||
unsigned int index);
|
||||
|
||||
HB_EXTERN hb_face_t *
|
||||
hb_directwrite_face_create_from_blob_or_fail (hb_blob_t *blob,
|
||||
unsigned int index);
|
||||
|
||||
HB_EXTERN IDWriteFontFace *
|
||||
hb_directwrite_face_get_dw_font_face (hb_face_t *face);
|
||||
|
||||
HB_EXTERN hb_font_t *
|
||||
hb_directwrite_font_create (IDWriteFontFace *dw_face);
|
||||
|
||||
HB_EXTERN IDWriteFontFace *
|
||||
hb_directwrite_font_get_dw_font_face (hb_font_t *font);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_directwrite_font_set_funcs (hb_font_t *font);
|
||||
|
||||
#ifndef HB_DISABLE_DEPRECATED
|
||||
|
||||
HB_DEPRECATED_FOR (hb_directwrite_face_get_dw_font_face)
|
||||
HB_EXTERN IDWriteFontFace *
|
||||
hb_directwrite_face_get_font_face (hb_face_t *face);
|
||||
|
||||
HB_EXTERN hb_font_t *
|
||||
hb_directwrite_font_create (IDWriteFont *dw_font);
|
||||
|
||||
HB_DEPRECATED
|
||||
HB_EXTERN IDWriteFont *
|
||||
hb_directwrite_font_get_dw_font (hb_font_t *font);
|
||||
|
||||
#endif
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
#endif /* HB_DIRECTWRITE_H */
|
||||
|
|
223
src/hb-directwrite.hh
Normal file
223
src/hb-directwrite.hh
Normal file
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HB_DIRECTWRITE_HH
|
||||
#define HB_DIRECTWRITE_HH
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#include "hb-directwrite.h"
|
||||
|
||||
#include "hb-mutex.hh"
|
||||
#include "hb-map.hh"
|
||||
|
||||
/*
|
||||
* DirectWrite font stream helpers
|
||||
*/
|
||||
|
||||
// Have a look at to NativeFontResourceDWrite.cpp in Mozilla
|
||||
|
||||
|
||||
/* Declare object creator for dynamic support of DWRITE */
|
||||
typedef HRESULT (WINAPI *t_DWriteCreateFactory)(
|
||||
DWRITE_FACTORY_TYPE factoryType,
|
||||
REFIID iid,
|
||||
IUnknown **factory
|
||||
);
|
||||
|
||||
class DWriteFontFileLoader : public IDWriteFontFileLoader
|
||||
{
|
||||
private:
|
||||
hb_reference_count_t mRefCount;
|
||||
hb_mutex_t mutex;
|
||||
hb_hashmap_t<uint64_t, IDWriteFontFileStream *> mFontStreams;
|
||||
uint64_t mNextFontFileKey = 0;
|
||||
public:
|
||||
DWriteFontFileLoader ()
|
||||
{
|
||||
mRefCount.init ();
|
||||
}
|
||||
|
||||
uint64_t RegisterFontFileStream (IDWriteFontFileStream *fontFileStream)
|
||||
{
|
||||
fontFileStream->AddRef ();
|
||||
hb_lock_t lock {mutex};
|
||||
mFontStreams.set (mNextFontFileKey, fontFileStream);
|
||||
return mNextFontFileKey++;
|
||||
}
|
||||
void UnregisterFontFileStream (uint64_t fontFileKey)
|
||||
{
|
||||
hb_lock_t lock {mutex};
|
||||
IDWriteFontFileStream *stream = mFontStreams.get (fontFileKey);
|
||||
if (stream)
|
||||
{
|
||||
mFontStreams.del (fontFileKey);
|
||||
stream->Release ();
|
||||
}
|
||||
}
|
||||
|
||||
// IUnknown interface
|
||||
IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject)
|
||||
{ return S_OK; }
|
||||
IFACEMETHOD_ (ULONG, AddRef) ()
|
||||
{
|
||||
return mRefCount.inc () + 1;
|
||||
}
|
||||
IFACEMETHOD_ (ULONG, Release) ()
|
||||
{
|
||||
signed refCount = mRefCount.dec () - 1;
|
||||
assert (refCount >= 0);
|
||||
if (refCount)
|
||||
return refCount;
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// IDWriteFontFileLoader methods
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
CreateStreamFromKey (void const* fontFileReferenceKey,
|
||||
uint32_t fontFileReferenceKeySize,
|
||||
OUT IDWriteFontFileStream** fontFileStream)
|
||||
{
|
||||
if (fontFileReferenceKeySize != sizeof (uint64_t))
|
||||
return E_INVALIDARG;
|
||||
uint64_t fontFileKey = * (uint64_t *) fontFileReferenceKey;
|
||||
IDWriteFontFileStream *stream = mFontStreams.get (fontFileKey);
|
||||
if (!stream)
|
||||
return E_FAIL;
|
||||
stream->AddRef ();
|
||||
*fontFileStream = stream;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
virtual ~DWriteFontFileLoader()
|
||||
{
|
||||
for (auto v : mFontStreams.values ())
|
||||
v->Release ();
|
||||
}
|
||||
};
|
||||
|
||||
class DWriteFontFileStream : public IDWriteFontFileStream
|
||||
{
|
||||
private:
|
||||
hb_reference_count_t mRefCount;
|
||||
hb_blob_t *mBlob;
|
||||
uint8_t *mData;
|
||||
unsigned mSize;
|
||||
DWriteFontFileLoader *mLoader;
|
||||
public:
|
||||
uint64_t fontFileKey;
|
||||
public:
|
||||
DWriteFontFileStream (hb_blob_t *blob);
|
||||
|
||||
// IUnknown interface
|
||||
IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject)
|
||||
{ return S_OK; }
|
||||
IFACEMETHOD_ (ULONG, AddRef) ()
|
||||
{
|
||||
return mRefCount.inc () + 1;
|
||||
}
|
||||
IFACEMETHOD_ (ULONG, Release) ()
|
||||
{
|
||||
signed refCount = mRefCount.dec () - 1;
|
||||
assert (refCount >= 0);
|
||||
if (refCount)
|
||||
return refCount;
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// IDWriteFontFileStream methods
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
ReadFileFragment (void const** fragmentStart,
|
||||
UINT64 fileOffset,
|
||||
UINT64 fragmentSize,
|
||||
OUT void** fragmentContext)
|
||||
{
|
||||
// We are required to do bounds checking.
|
||||
if (fileOffset + fragmentSize > mSize) return E_FAIL;
|
||||
|
||||
// truncate the 64 bit fileOffset to size_t sized index into mData
|
||||
size_t index = static_cast<size_t> (fileOffset);
|
||||
|
||||
// We should be alive for the duration of this.
|
||||
*fragmentStart = &mData[index];
|
||||
*fragmentContext = nullptr;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
virtual void STDMETHODCALLTYPE
|
||||
ReleaseFileFragment (void* fragmentContext) {}
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
GetFileSize (OUT UINT64* fileSize)
|
||||
{
|
||||
*fileSize = mSize;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
GetLastWriteTime (OUT UINT64* lastWriteTime) { return E_NOTIMPL; }
|
||||
|
||||
virtual ~DWriteFontFileStream();
|
||||
};
|
||||
|
||||
struct hb_directwrite_global_t
|
||||
{
|
||||
hb_directwrite_global_t ()
|
||||
{
|
||||
HRESULT hr = DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
|
||||
(IUnknown**) &dwriteFactory);
|
||||
|
||||
if (unlikely (hr != S_OK))
|
||||
return;
|
||||
|
||||
fontFileLoader = new DWriteFontFileLoader ();
|
||||
dwriteFactory->RegisterFontFileLoader (fontFileLoader);
|
||||
|
||||
success = true;
|
||||
}
|
||||
~hb_directwrite_global_t ()
|
||||
{
|
||||
if (fontFileLoader)
|
||||
fontFileLoader->Release ();
|
||||
if (dwriteFactory)
|
||||
dwriteFactory->Release ();
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
IDWriteFactory *dwriteFactory;
|
||||
DWriteFontFileLoader *fontFileLoader;
|
||||
};
|
||||
|
||||
|
||||
HB_INTERNAL hb_directwrite_global_t *
|
||||
get_directwrite_global ();
|
||||
|
||||
HB_INTERNAL IDWriteFontFace *
|
||||
dw_face_create (hb_blob_t *blob, unsigned index);
|
||||
|
||||
|
||||
#endif /* HB_DIRECTWRITE_HH */
|
|
@ -41,9 +41,16 @@ HB_BEGIN_DECLS
|
|||
* @path_start_y: Y component of the start of current path
|
||||
* @current_x: X component of current point
|
||||
* @current_y: Y component of current point
|
||||
* @slant_xy: Slanting factor for synthetic oblique, Since: 11.0.0
|
||||
*
|
||||
* Current drawing state.
|
||||
*
|
||||
* The @slant_xy is a slanting factor for synthetic oblique. If the font's
|
||||
* oblique angle is not 0, this factor is used to slant the drawing. For
|
||||
* fonts with uniform x and y scales, this factor is calculated as
|
||||
* tan(oblique_angle). For fonts with non-uniform scales, this factor is
|
||||
* calculated as tan(oblique_angle) * x_scale / y_scale, or 0 if y_scale is 0.
|
||||
*
|
||||
* Since: 4.0.0
|
||||
**/
|
||||
typedef struct hb_draw_state_t {
|
||||
|
@ -55,6 +62,8 @@ typedef struct hb_draw_state_t {
|
|||
float current_x;
|
||||
float current_y;
|
||||
|
||||
float slant_xy;
|
||||
|
||||
/*< private >*/
|
||||
hb_var_num_t reserved1;
|
||||
hb_var_num_t reserved2;
|
||||
|
@ -62,7 +71,6 @@ typedef struct hb_draw_state_t {
|
|||
hb_var_num_t reserved4;
|
||||
hb_var_num_t reserved5;
|
||||
hb_var_num_t reserved6;
|
||||
hb_var_num_t reserved7;
|
||||
} hb_draw_state_t;
|
||||
|
||||
/**
|
||||
|
@ -70,7 +78,7 @@ typedef struct hb_draw_state_t {
|
|||
*
|
||||
* The default #hb_draw_state_t at the start of glyph drawing.
|
||||
*/
|
||||
#define HB_DRAW_STATE_DEFAULT {0, 0.f, 0.f, 0.f, 0.f, {0.}, {0.}, {0.}, {0.}, {0.}, {0.}, {0.}}
|
||||
#define HB_DRAW_STATE_DEFAULT {0, 0.f, 0.f, 0.f, 0.f, 0.f, {0.}, {0.}, {0.}, {0.}, {0.}, {0.}}
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -99,6 +99,10 @@ struct hb_draw_funcs_t
|
|||
float to_x, float to_y)
|
||||
{
|
||||
if (unlikely (st.path_open)) close_path (draw_data, st);
|
||||
|
||||
if (st.slant_xy)
|
||||
to_x += to_y * st.slant_xy;
|
||||
|
||||
st.current_x = to_x;
|
||||
st.current_y = to_y;
|
||||
}
|
||||
|
@ -109,7 +113,12 @@ struct hb_draw_funcs_t
|
|||
float to_x, float to_y)
|
||||
{
|
||||
if (unlikely (!st.path_open)) start_path (draw_data, st);
|
||||
|
||||
if (st.slant_xy)
|
||||
to_x += to_y * st.slant_xy;
|
||||
|
||||
emit_line_to (draw_data, st, to_x, to_y);
|
||||
|
||||
st.current_x = to_x;
|
||||
st.current_y = to_y;
|
||||
}
|
||||
|
@ -121,7 +130,15 @@ struct hb_draw_funcs_t
|
|||
float to_x, float to_y)
|
||||
{
|
||||
if (unlikely (!st.path_open)) start_path (draw_data, st);
|
||||
|
||||
if (st.slant_xy)
|
||||
{
|
||||
control_x += control_y * st.slant_xy;
|
||||
to_x += to_y * st.slant_xy;
|
||||
}
|
||||
|
||||
emit_quadratic_to (draw_data, st, control_x, control_y, to_x, to_y);
|
||||
|
||||
st.current_x = to_x;
|
||||
st.current_y = to_y;
|
||||
}
|
||||
|
@ -134,7 +151,16 @@ struct hb_draw_funcs_t
|
|||
float to_x, float to_y)
|
||||
{
|
||||
if (unlikely (!st.path_open)) start_path (draw_data, st);
|
||||
|
||||
if (st.slant_xy)
|
||||
{
|
||||
control1_x += control1_y * st.slant_xy;
|
||||
control2_x += control2_y * st.slant_xy;
|
||||
to_x += to_y * st.slant_xy;
|
||||
}
|
||||
|
||||
emit_cubic_to (draw_data, st, control1_x, control1_y, control2_x, control2_y, to_x, to_y);
|
||||
|
||||
st.current_x = to_x;
|
||||
st.current_y = to_y;
|
||||
}
|
||||
|
@ -168,46 +194,32 @@ DECLARE_NULL_INSTANCE (hb_draw_funcs_t);
|
|||
|
||||
struct hb_draw_session_t
|
||||
{
|
||||
hb_draw_session_t (hb_draw_funcs_t *funcs_, void *draw_data_, float slant_ = 0.f)
|
||||
: slant {slant_}, not_slanted {slant == 0.f},
|
||||
funcs {funcs_}, draw_data {draw_data_}, st HB_DRAW_STATE_DEFAULT
|
||||
{}
|
||||
hb_draw_session_t (hb_draw_funcs_t *funcs_, void *draw_data_, float slant_xy = 0.f)
|
||||
: funcs {funcs_}, draw_data {draw_data_}, st HB_DRAW_STATE_DEFAULT
|
||||
{ st.slant_xy = slant_xy; }
|
||||
|
||||
~hb_draw_session_t () { close_path (); }
|
||||
|
||||
HB_ALWAYS_INLINE
|
||||
void move_to (float to_x, float to_y)
|
||||
{
|
||||
if (likely (not_slanted))
|
||||
funcs->move_to (draw_data, st,
|
||||
to_x, to_y);
|
||||
else
|
||||
funcs->move_to (draw_data, st,
|
||||
to_x + to_y * slant, to_y);
|
||||
funcs->move_to (draw_data, st,
|
||||
to_x, to_y);
|
||||
}
|
||||
HB_ALWAYS_INLINE
|
||||
void line_to (float to_x, float to_y)
|
||||
{
|
||||
if (likely (not_slanted))
|
||||
funcs->line_to (draw_data, st,
|
||||
to_x, to_y);
|
||||
else
|
||||
funcs->line_to (draw_data, st,
|
||||
to_x + to_y * slant, to_y);
|
||||
funcs->line_to (draw_data, st,
|
||||
to_x, to_y);
|
||||
}
|
||||
void
|
||||
HB_ALWAYS_INLINE
|
||||
quadratic_to (float control_x, float control_y,
|
||||
float to_x, float to_y)
|
||||
{
|
||||
if (likely (not_slanted))
|
||||
funcs->quadratic_to (draw_data, st,
|
||||
control_x, control_y,
|
||||
to_x, to_y);
|
||||
else
|
||||
funcs->quadratic_to (draw_data, st,
|
||||
control_x + control_y * slant, control_y,
|
||||
to_x + to_y * slant, to_y);
|
||||
funcs->quadratic_to (draw_data, st,
|
||||
control_x, control_y,
|
||||
to_x, to_y);
|
||||
}
|
||||
void
|
||||
HB_ALWAYS_INLINE
|
||||
|
@ -215,16 +227,10 @@ struct hb_draw_session_t
|
|||
float control2_x, float control2_y,
|
||||
float to_x, float to_y)
|
||||
{
|
||||
if (likely (not_slanted))
|
||||
funcs->cubic_to (draw_data, st,
|
||||
control1_x, control1_y,
|
||||
control2_x, control2_y,
|
||||
to_x, to_y);
|
||||
else
|
||||
funcs->cubic_to (draw_data, st,
|
||||
control1_x + control1_y * slant, control1_y,
|
||||
control2_x + control2_y * slant, control2_y,
|
||||
to_x + to_y * slant, to_y);
|
||||
funcs->cubic_to (draw_data, st,
|
||||
control1_x, control1_y,
|
||||
control2_x, control2_y,
|
||||
to_x, to_y);
|
||||
}
|
||||
HB_ALWAYS_INLINE
|
||||
void close_path ()
|
||||
|
@ -233,8 +239,6 @@ struct hb_draw_session_t
|
|||
}
|
||||
|
||||
public:
|
||||
float slant;
|
||||
bool not_slanted;
|
||||
hb_draw_funcs_t *funcs;
|
||||
void *draw_data;
|
||||
hb_draw_state_t st;
|
||||
|
|
238
src/hb-face.cc
238
src/hb-face.cc
|
@ -34,6 +34,16 @@
|
|||
#include "hb-ot-face.hh"
|
||||
#include "hb-ot-cmap-table.hh"
|
||||
|
||||
#ifdef HAVE_FREETYPE
|
||||
#include "hb-ft.h"
|
||||
#endif
|
||||
#ifdef HAVE_CORETEXT
|
||||
#include "hb-coretext.h"
|
||||
#endif
|
||||
#ifdef HAVE_DIRECTWRITE
|
||||
#include "hb-directwrite.h"
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-face
|
||||
|
@ -72,14 +82,14 @@ hb_face_count (hb_blob_t *blob)
|
|||
if (unlikely (!blob))
|
||||
return 0;
|
||||
|
||||
/* TODO We shouldn't be sanitizing blob. Port to run sanitizer and return if not sane. */
|
||||
/* Make API signature const after. */
|
||||
hb_blob_t *sanitized = hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob));
|
||||
const OT::OpenTypeFontFile& ot = *sanitized->as<OT::OpenTypeFontFile> ();
|
||||
unsigned int ret = ot.get_face_count ();
|
||||
hb_blob_destroy (sanitized);
|
||||
hb_sanitize_context_t c (blob);
|
||||
|
||||
return ret;
|
||||
const char *start = hb_blob_get_data (blob, nullptr);
|
||||
auto *ot = reinterpret_cast<OT::OpenTypeFontFile *> (const_cast<char *> (start));
|
||||
if (unlikely (!ot->sanitize (&c)))
|
||||
return 0;
|
||||
|
||||
return ot->get_face_count ();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -318,7 +328,209 @@ hb_face_create_from_file_or_fail (const char *file_name,
|
|||
|
||||
return face;
|
||||
}
|
||||
|
||||
static struct supported_face_loaders_t {
|
||||
char name[16];
|
||||
hb_face_t * (*from_file) (const char *font_file, unsigned face_index);
|
||||
hb_face_t * (*from_blob) (hb_blob_t *blob, unsigned face_index);
|
||||
} supported_face_loaders[] =
|
||||
{
|
||||
{"ot",
|
||||
#ifndef HB_NO_OPEN
|
||||
hb_face_create_from_file_or_fail,
|
||||
#else
|
||||
nullptr,
|
||||
#endif
|
||||
hb_face_create_or_fail
|
||||
},
|
||||
#ifdef HAVE_FREETYPE
|
||||
{"ft",
|
||||
hb_ft_face_create_from_file_or_fail,
|
||||
hb_ft_face_create_from_blob_or_fail
|
||||
},
|
||||
#endif
|
||||
#ifdef HAVE_CORETEXT
|
||||
{"coretext",
|
||||
hb_coretext_face_create_from_file_or_fail,
|
||||
hb_coretext_face_create_from_blob_or_fail
|
||||
},
|
||||
#endif
|
||||
#ifdef HAVE_DIRECTWRITE
|
||||
{"directwrite",
|
||||
hb_directwrite_face_create_from_file_or_fail,
|
||||
hb_directwrite_face_create_from_blob_or_fail
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
static const char *get_default_loader_name ()
|
||||
{
|
||||
static hb_atomic_t<const char *> static_loader_name;
|
||||
const char *loader_name = static_loader_name.get_acquire ();
|
||||
if (!loader_name)
|
||||
{
|
||||
loader_name = getenv ("HB_FACE_LOADER");
|
||||
if (!loader_name)
|
||||
loader_name = "";
|
||||
if (!static_loader_name.cmpexch (nullptr, loader_name))
|
||||
loader_name = static_loader_name.get_acquire ();
|
||||
}
|
||||
return loader_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_face_create_from_file_or_fail_using:
|
||||
* @file_name: A font filename
|
||||
* @index: The index of the face within the file
|
||||
* @loader_name: (nullable): The name of the loader to use, or `NULL`
|
||||
*
|
||||
* A thin wrapper around the face loader functions registered with HarfBuzz.
|
||||
* If @loader_name is `NULL` or the empty string, the first available loader
|
||||
* is used.
|
||||
*
|
||||
* For example, the FreeType ("ft") loader might be able to load
|
||||
* WOFF and WOFF2 files if FreeType is built with those features,
|
||||
* whereas the OpenType ("ot") loader will not.
|
||||
*
|
||||
* Return value: (transfer full): The new face object, or `NULL` if
|
||||
* the file cannot be read or the loader fails to load the face.
|
||||
*
|
||||
* Since: 11.0.0
|
||||
**/
|
||||
hb_face_t *
|
||||
hb_face_create_from_file_or_fail_using (const char *file_name,
|
||||
unsigned int index,
|
||||
const char *loader_name)
|
||||
{
|
||||
// Duplicated in hb_face_create_or_fail_using
|
||||
bool retry = false;
|
||||
if (!loader_name || !*loader_name)
|
||||
{
|
||||
loader_name = get_default_loader_name ();
|
||||
retry = true;
|
||||
}
|
||||
if (loader_name && !*loader_name) loader_name = nullptr;
|
||||
|
||||
retry:
|
||||
for (unsigned i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++)
|
||||
{
|
||||
if (!loader_name || (supported_face_loaders[i].from_file && !strcmp (supported_face_loaders[i].name, loader_name)))
|
||||
return supported_face_loaders[i].from_file (file_name, index);
|
||||
}
|
||||
|
||||
if (retry)
|
||||
{
|
||||
retry = false;
|
||||
loader_name = nullptr;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_face_create_or_fail_using:
|
||||
* @blob: #hb_blob_t to work upon
|
||||
* @index: The index of the face within @blob
|
||||
* @loader_name: (nullable): The name of the loader to use, or `NULL`
|
||||
*
|
||||
* A thin wrapper around the face loader functions registered with HarfBuzz.
|
||||
* If @loader_name is `NULL` or the empty string, the first available loader
|
||||
* is used.
|
||||
*
|
||||
* For example, the FreeType ("ft") loader might be able to load
|
||||
* WOFF and WOFF2 files if FreeType is built with those features,
|
||||
* whereas the OpenType ("ot") loader will not.
|
||||
*
|
||||
* Return value: (transfer full): The new face object, or `NULL` if
|
||||
* the loader fails to load the face.
|
||||
*
|
||||
* Since: 11.0.0
|
||||
**/
|
||||
hb_face_t *
|
||||
hb_face_create_or_fail_using (hb_blob_t *blob,
|
||||
unsigned int index,
|
||||
const char *loader_name)
|
||||
{
|
||||
// Duplicated in hb_face_create_from_file_or_fail_using
|
||||
bool retry = false;
|
||||
if (!loader_name || !*loader_name)
|
||||
{
|
||||
loader_name = get_default_loader_name ();
|
||||
retry = true;
|
||||
}
|
||||
if (loader_name && !*loader_name) loader_name = nullptr;
|
||||
|
||||
retry:
|
||||
for (unsigned i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++)
|
||||
{
|
||||
if (!loader_name || (supported_face_loaders[i].from_blob && !strcmp (supported_face_loaders[i].name, loader_name)))
|
||||
return supported_face_loaders[i].from_blob (blob, index);
|
||||
}
|
||||
|
||||
if (retry)
|
||||
{
|
||||
retry = false;
|
||||
loader_name = nullptr;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static inline void free_static_face_loader_list ();
|
||||
|
||||
static const char * const nil_face_loader_list[] = {nullptr};
|
||||
|
||||
static struct hb_face_loader_list_lazy_loader_t : hb_lazy_loader_t<const char *,
|
||||
hb_face_loader_list_lazy_loader_t>
|
||||
{
|
||||
static const char ** create ()
|
||||
{
|
||||
const char **face_loader_list = (const char **) hb_calloc (1 + ARRAY_LENGTH (supported_face_loaders), sizeof (const char *));
|
||||
if (unlikely (!face_loader_list))
|
||||
return nullptr;
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++)
|
||||
face_loader_list[i] = supported_face_loaders[i].name;
|
||||
face_loader_list[i] = nullptr;
|
||||
|
||||
hb_atexit (free_static_face_loader_list);
|
||||
|
||||
return face_loader_list;
|
||||
}
|
||||
static void destroy (const char **l)
|
||||
{ hb_free (l); }
|
||||
static const char * const * get_null ()
|
||||
{ return nil_face_loader_list; }
|
||||
} static_face_loader_list;
|
||||
|
||||
static inline
|
||||
void free_static_face_loader_list ()
|
||||
{
|
||||
static_face_loader_list.free_instance ();
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_face_list_loaders:
|
||||
*
|
||||
* Retrieves the list of face loaders supported by HarfBuzz.
|
||||
*
|
||||
* Return value: (transfer none) (array zero-terminated=1): a
|
||||
* `NULL`-terminated array of supported face loaders
|
||||
* constant strings. The returned array is owned by HarfBuzz
|
||||
* and should not be modified or freed.
|
||||
*
|
||||
* Since: 11.0.0
|
||||
**/
|
||||
const char **
|
||||
hb_face_list_loaders ()
|
||||
{
|
||||
return static_face_loader_list.get_unconst ();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* hb_face_get_empty:
|
||||
|
@ -460,7 +672,7 @@ hb_face_make_immutable (hb_face_t *face)
|
|||
* Since: 0.9.2
|
||||
**/
|
||||
hb_bool_t
|
||||
hb_face_is_immutable (const hb_face_t *face)
|
||||
hb_face_is_immutable (hb_face_t *face)
|
||||
{
|
||||
return hb_object_is_immutable (face);
|
||||
}
|
||||
|
@ -522,11 +734,15 @@ hb_face_reference_blob (hb_face_t *face)
|
|||
for (unsigned offset = 0; offset < total_count; offset += count)
|
||||
{
|
||||
hb_face_get_table_tags (face, offset, &count, tags);
|
||||
if (unlikely (!count))
|
||||
break; // Allocation error
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
{
|
||||
hb_blob_t *table = hb_face_reference_table (face, tags[i]);
|
||||
hb_face_builder_add_table (builder, tags[i], table);
|
||||
hb_blob_destroy (table);
|
||||
if (unlikely (!tags[i]))
|
||||
continue;
|
||||
hb_blob_t *table = hb_face_reference_table (face, tags[i]);
|
||||
hb_face_builder_add_table (builder, tags[i], table);
|
||||
hb_blob_destroy (table);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -63,10 +63,24 @@ HB_EXTERN hb_face_t *
|
|||
hb_face_create_or_fail (hb_blob_t *blob,
|
||||
unsigned int index);
|
||||
|
||||
HB_EXTERN hb_face_t *
|
||||
hb_face_create_or_fail_using (hb_blob_t *blob,
|
||||
unsigned int index,
|
||||
const char *loader_name);
|
||||
|
||||
HB_EXTERN hb_face_t *
|
||||
hb_face_create_from_file_or_fail (const char *file_name,
|
||||
unsigned int index);
|
||||
|
||||
HB_EXTERN hb_face_t *
|
||||
hb_face_create_from_file_or_fail_using (const char *file_name,
|
||||
unsigned int index,
|
||||
const char *loader_name);
|
||||
|
||||
HB_EXTERN const char **
|
||||
hb_face_list_loaders (void);
|
||||
|
||||
|
||||
/**
|
||||
* hb_reference_table_func_t:
|
||||
* @face: an #hb_face_t to reference table for
|
||||
|
@ -117,7 +131,7 @@ HB_EXTERN void
|
|||
hb_face_make_immutable (hb_face_t *face);
|
||||
|
||||
HB_EXTERN hb_bool_t
|
||||
hb_face_is_immutable (const hb_face_t *face);
|
||||
hb_face_is_immutable (hb_face_t *face);
|
||||
|
||||
|
||||
HB_EXTERN hb_blob_t *
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue