fontisan 0.4.46 → 0.4.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. data/BENCHMARKS.md +56 -0
  3. data/CHANGELOG.md +12 -0
  4. data/Cargo.lock +550 -0
  5. data/Cargo.toml +12 -0
  6. data/Gemfile +10 -0
  7. data/README.adoc +52 -0
  8. data/Rakefile +5 -1
  9. data/benchmark/baseline.json +5 -0
  10. data/benchmark/ci_gate.rb +217 -0
  11. data/benchmark/corpus/harness.rb +175 -0
  12. data/benchmark/corpus/ops.rb +150 -0
  13. data/benchmark/corpus/run.rb +182 -0
  14. data/benchmark/corpus/scan_child.rb +8 -0
  15. data/benchmark/corpus/tiers.rb +176 -0
  16. data/benchmark/tier_baseline.json +12 -0
  17. data/docs/.vitepress/config.ts +2 -1
  18. data/docs/guide/engines.md +117 -0
  19. data/docs/reference-facade.md +130 -0
  20. data/ext/fontisan_cdylib/Cargo.lock +313 -0
  21. data/ext/fontisan_cdylib/Cargo.toml +18 -0
  22. data/ext/fontisan_cdylib/build.rs +22 -0
  23. data/ext/fontisan_cdylib/extconf.rb +36 -0
  24. data/ext/fontisan_cdylib/src/lib.rs +13 -0
  25. data/ext/fontisan_native/Cargo.toml +21 -0
  26. data/ext/fontisan_native/build.rs +22 -0
  27. data/ext/fontisan_native/clippy.toml +10 -0
  28. data/ext/fontisan_native/extconf.rb +59 -0
  29. data/ext/fontisan_native/src/lib.rs +463 -0
  30. data/lib/fontisan/audit/checks/cmap_check.rb +7 -0
  31. data/lib/fontisan/audit/checks/hinting_check.rb +1 -1
  32. data/lib/fontisan/audit/checks/maxp_check.rb +1 -1
  33. data/lib/fontisan/audit/checks/opentype_conformance_check.rb +5 -2
  34. data/lib/fontisan/base_collection.rb +30 -0
  35. data/lib/fontisan/byte_ops.rb +219 -0
  36. data/lib/fontisan/cli.rb +5 -5
  37. data/lib/fontisan/commands/audit_command.rb +38 -43
  38. data/lib/fontisan/commands/convert_command.rb +53 -0
  39. data/lib/fontisan/commands/instance_command.rb +75 -0
  40. data/lib/fontisan/commands/subset_command.rb +43 -0
  41. data/lib/fontisan/commands/unpack_command.rb +56 -0
  42. data/lib/fontisan/converters/cff_table_builder.rb +1 -1
  43. data/lib/fontisan/converters/collection_converter.rb +13 -5
  44. data/lib/fontisan/converters/format_converter.rb +1 -1
  45. data/lib/fontisan/converters/woff2_encoder.rb +8 -6
  46. data/lib/fontisan/converters/woff_writer.rb +6 -5
  47. data/lib/fontisan/engine.rb +350 -0
  48. data/lib/fontisan/ffi/client.rb +121 -0
  49. data/lib/fontisan/ffi.rb +343 -0
  50. data/lib/fontisan/ffi_platform.rb +24 -0
  51. data/lib/fontisan/font_loader.rb +5 -1
  52. data/lib/fontisan/font_writer.rb +13 -1
  53. data/lib/fontisan/native.rb +231 -0
  54. data/lib/fontisan/pipeline/transformation_pipeline.rb +10 -8
  55. data/lib/fontisan/pipeline.rb +1 -1
  56. data/lib/fontisan/reference/table_digests.rb +251 -0
  57. data/lib/fontisan/reference.rb +619 -0
  58. data/lib/fontisan/scan.rb +372 -0
  59. data/lib/fontisan/sfnt_directory.rb +41 -0
  60. data/lib/fontisan/sfnt_font.rb +16 -6
  61. data/lib/fontisan/subset/builder.rb +2 -1
  62. data/lib/fontisan/tables/cff/charstring.rb +16 -0
  63. data/lib/fontisan/tables/cff.rb +15 -5
  64. data/lib/fontisan/tables/cmap.rb +11 -1
  65. data/lib/fontisan/tables/glyf.rb +4 -6
  66. data/lib/fontisan/tables/gpos.rb +7 -0
  67. data/lib/fontisan/tables/gsub.rb +7 -0
  68. data/lib/fontisan/tables/layout_common.rb +172 -0
  69. data/lib/fontisan/tables/name.rb +10 -4
  70. data/lib/fontisan/utilities/brotli_wrapper.rb +39 -4
  71. data/lib/fontisan/validators/opentype_validator.rb +15 -3
  72. data/lib/fontisan/variable/instancer.rb +23 -192
  73. data/lib/fontisan/variable/static_font_builder.rb +4 -1
  74. data/lib/fontisan/variable/table_updater.rb +4 -2
  75. data/lib/fontisan/variation/instance_generator.rb +3 -149
  76. data/lib/fontisan/variation/instancing/axis_space.rb +136 -0
  77. data/lib/fontisan/variation/instancing/glyph_outline.rb +204 -0
  78. data/lib/fontisan/variation/instancing/gvar_reader.rb +146 -0
  79. data/lib/fontisan/variation/instancing/item_variation_store.rb +92 -0
  80. data/lib/fontisan/variation/instancing/name_rewriter.rb +90 -0
  81. data/lib/fontisan/variation/instancing/true_type_instancer.rb +326 -0
  82. data/lib/fontisan/variation/instancing.rb +20 -0
  83. data/lib/fontisan/variation/variable_svg_generator.rb +19 -1
  84. data/lib/fontisan/variation.rb +1 -0
  85. data/lib/fontisan/version.rb +1 -1
  86. data/lib/fontisan/woff2/collection_decoder.rb +15 -1
  87. data/lib/fontisan/woff2/collection_encoder.rb +29 -6
  88. data/lib/fontisan/woff2/encoder_rules.rb +12 -4
  89. data/lib/fontisan/woff2/glyf_loca_reconstruct.rb +1 -1
  90. data/lib/fontisan/woff2_collection.rb +7 -5
  91. data/lib/fontisan/woff2_font.rb +12 -3
  92. data/lib/fontisan/woff_container.rb +83 -0
  93. data/lib/fontisan/woff_font.rb +24 -20
  94. data/lib/fontisan.rb +24 -1
  95. data/rakelib/bench.rake +9 -0
  96. data/rakelib/cdylib.rake +39 -0
  97. data/rakelib/corpus.rake +272 -0
  98. data/rakelib/corpus_convert.rake +43 -0
  99. data/rakelib/corpus_goldens.rake +22 -0
  100. data/rakelib/corpus_malformed.rake +20 -0
  101. data/rakelib/corpus_scan.rake +24 -0
  102. data/rakelib/java.rake +61 -0
  103. data/rakelib/native.rake +43 -0
  104. data/scripts/build-woff2.sh +57 -0
  105. data/scripts/corpus/generate_convert_goldens.rb +478 -0
  106. data/scripts/corpus/generate_goldens.rb +282 -0
  107. data/scripts/corpus/generate_malformed_goldens.rb +254 -0
  108. data/scripts/corpus/generate_scan_goldens.rb +98 -0
  109. data/scripts/tier_fallback.rb +219 -0
  110. data/scripts/tier_smoke.rb +64 -0
  111. metadata +75 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1866983941321f8342976513ef0fb988454641cd88e677c9f8ea5c5811fe4368
4
- data.tar.gz: 959ca2b7cec09514b960b1f9c649ca9b6f3d9716dfd87c31dfa8155ae54d6ac2
3
+ metadata.gz: 1acd9a7fdcd6fc469e7d8ca2614a8e5e036248e31fa297d1056f151b2796ab27
4
+ data.tar.gz: 6c9593f9cce03a5aba93dedf68a1c3606e25bf7f2deb5991443f048cb51c753e
5
5
  SHA512:
6
- metadata.gz: 8515b8d576d88acd19737ccfb14fc5aea468c7ac94b1242beb09757a6a45c11f9846caf8e64df1558ccd472f31a74ceee3fae415471861c8fe0b0520802d86fd
7
- data.tar.gz: b025f9cb74a3a4059367d33453113838fbde355ff434f51879a97d19a134e5753d640b6b2460741d3999a69b79ce16e5bc78db3e5e6e929e85974a77e5cebca2
6
+ metadata.gz: 5db866166488d311c45a6fc0265ba3da422d28717469bc5303a06028dc2c50038d84d953d850303e967d55c59cbc1f3113a1ce364a9b0b2eab3be3f40e94845d
7
+ data.tar.gz: bf0cecbde3bc1ebc7312ada4fafc112e8e6e905fe682a1f33ee46645cf8e54eadcad15c768d1a5b22212cd1ddc9b9928795e7bf94c044b0e528bf517920277ae
data/BENCHMARKS.md ADDED
@@ -0,0 +1,56 @@
1
+ # Benchmarks
2
+
3
+ Reference corpus `ci` tier benches for the #157 operations (`rake bench`).
4
+
5
+ - fontisan SHA: `6806181894f8dd9d4fa4cba3ea3cf3ffef59d341`
6
+ - Ruby: 3.4.8 (arm64-darwin25)
7
+ - Runner: darwin25, Apple M2, 8 cores
8
+ - Rounds: 5 (median per op); each op is the fastest of repeated calls (at least 3 calls or 0.25 s of measured time)
9
+
10
+ | operation | median |
11
+ |---|---|
12
+ | table_parse | 5.9 ms |
13
+ | names | 5.0 ms |
14
+ | cmap_coverage | 2.7 ms |
15
+ | audit_file | 368.2 ms |
16
+ | audit_dir | 496.3 ms |
17
+ | scan_dir | 265.6 ms |
18
+ | vf_instance | 141.6 ms |
19
+ | woff2_decode | 93.5 ms |
20
+ | convert_roundtrip | 109.2 ms |
21
+ | woff2_encode | 994.6 ms |
22
+ | scan_peak_rss (directory scan) | 60.4 MB |
23
+
24
+ ## Engine tier factors
25
+
26
+ - Ruby: 3.4.8 (arm64-darwin25); local macOS arm64 (Apple M2), not CI
27
+ - fontisan SHA: `d8e13aae38212cb0507cee03d6ce8fbbf53061e2`
28
+
29
+ Median of 5+ interleaved rounds, one engine per run (`FONTISAN_ENGINE`, strict). Factor = ruby time / tier time (above 1.00x is faster than Ruby; RSS rows show tier / ruby). Hard floor: native and ffi factors on audit_file, audit_dir, scan_dir must be at least 1.00x and their peak RSS must not exceed ruby's by more than 3%. Other columns are reported, not gated.
30
+
31
+ | metric | ruby | native | ffi | native factor | ffi factor | status |
32
+ |---|---|---|---|---|---|---|
33
+ | audit_file | 371.9 ms | 12.3 ms | 12.3 ms | 30.26x | 30.13x | ok |
34
+ | audit_dir | 481.6 ms | 58.6 ms | 58.2 ms | 8.22x | 8.27x | ok: gated |
35
+ | scan_dir | 239.0 ms | 60.7 ms | 58.2 ms | 3.94x | 4.11x | ok: gated |
36
+ | scan_peak_rss_kb | 58.5 MB | 56.3 MB | 57.5 MB | 0.96x | 0.98x | ok: gated |
37
+
38
+ **RESULT: PASS**
39
+
40
+ The table above is the local macOS arm64 measurement. CI measures the other platforms (`perf-gate.yml`, job `tiers`; one `perf-tiers-<platform>` artifact each); their rows are added when those runs are green.
41
+
42
+ ## Published factors per platform (CI)
43
+
44
+ Native factor (ruby time / native time) from the `perf-gate.yml` `tiers` jobs, run 42807490330 on fontisan `5e1bd0fc0b3f2373ca6d53d7360e28d4497bbfe2`. Median of 5+ interleaved rounds, one engine per run, hard floor 1.00x on audit_file, audit_dir and scan_dir and native peak RSS at or below ruby's. Every cell below passed the floor.
45
+
46
+ | platform (runner) | audit_file | audit_dir | scan_dir | scan peak RSS (native / ruby) |
47
+ |---|---|---|---|---|
48
+ | x86_64-linux (ubuntu-22.04) | 44.80x | 21.32x | 15.39x | 0.86x |
49
+ | x86_64-linux-musl (alpine) | 25.91x | 14.67x | 11.27x | 0.89x |
50
+ | aarch64-linux (ubuntu-22.04-arm) | 46.80x | 11.32x | 8.27x | 0.88x |
51
+ | x86_64-darwin (macos-15-intel) | 39.82x | 10.25x | 9.51x | 0.94x |
52
+ | x64-mingw-ucrt (windows-2025) | 30.32x | 17.12x | 10.89x | 0.85x |
53
+ | arm64-darwin (macos-15) | 40.39x | 6.81x | 5.51x | 0.91x |
54
+
55
+ All six rows now come from CI. arm64-darwin has no committed baseline yet, so it is checked against the 1.00x floor only. The lowest published native factor on a gated operation is 5.51x (scan_dir, arm64-darwin).
56
+
data/CHANGELOG.md CHANGED
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ### Changed
11
+
12
+ - The default engine is now `FONTISAN_ENGINE=auto`: installs with a native tier
13
+ serve the path-based `Fontisan::Reference` operations from it (native, then
14
+ ffi), and installs without one fall back to Ruby with no toolchain needed.
15
+ Set `FONTISAN_ENGINE=ruby` to opt out. Engine: fontisan-rs at git rev
16
+ `daffb3f45b67517e924a3e5d0e113a2ecbde9959` (crate version 0.0.0, not yet on
17
+ crates.io), bundled as the magnus extension and the C-ABI shared library.
18
+ Platform gems: `x86_64-linux`, `x86_64-linux-musl`, `arm64-darwin`,
19
+ `x86_64-darwin`, `x64-mingw-ucrt`; the `java` gem carries the shared library
20
+ for JRuby. Measured native factors per platform are in `BENCHMARKS.md`.
21
+
10
22
  ### Removed
11
23
 
12
24
  - Audit/UCD documentation residue from the v0.3.0 audit/UCD subsystem
data/Cargo.lock ADDED
@@ -0,0 +1,550 @@
1
+ # This file is automatically @generated by Cargo.
2
+ # It is not intended for manual editing.
3
+ version = 4
4
+
5
+ [[package]]
6
+ name = "adler2"
7
+ version = "2.0.1"
8
+ source = "registry+https://github.com/rust-lang/crates.io-index"
9
+ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
10
+
11
+ [[package]]
12
+ name = "aho-corasick"
13
+ version = "1.1.5"
14
+ source = "registry+https://github.com/rust-lang/crates.io-index"
15
+ checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba"
16
+ dependencies = [
17
+ "memchr",
18
+ ]
19
+
20
+ [[package]]
21
+ name = "alloc-no-stdlib"
22
+ version = "2.0.4"
23
+ source = "registry+https://github.com/rust-lang/crates.io-index"
24
+ checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3"
25
+
26
+ [[package]]
27
+ name = "alloc-stdlib"
28
+ version = "0.2.4"
29
+ source = "registry+https://github.com/rust-lang/crates.io-index"
30
+ checksum = "0e76a019e91224d279006ff972f1e984179a6e9feb050adba6ce8274aef23195"
31
+ dependencies = [
32
+ "alloc-no-stdlib",
33
+ ]
34
+
35
+ [[package]]
36
+ name = "bindgen"
37
+ version = "0.72.1"
38
+ source = "registry+https://github.com/rust-lang/crates.io-index"
39
+ checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
40
+ dependencies = [
41
+ "bitflags",
42
+ "cexpr",
43
+ "clang-sys",
44
+ "itertools",
45
+ "proc-macro2",
46
+ "quote",
47
+ "regex",
48
+ "rustc-hash",
49
+ "shlex",
50
+ "syn 2.0.119",
51
+ ]
52
+
53
+ [[package]]
54
+ name = "bitflags"
55
+ version = "2.13.2"
56
+ source = "registry+https://github.com/rust-lang/crates.io-index"
57
+ checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06"
58
+
59
+ [[package]]
60
+ name = "block-buffer"
61
+ version = "0.10.4"
62
+ source = "registry+https://github.com/rust-lang/crates.io-index"
63
+ checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
64
+ dependencies = [
65
+ "generic-array",
66
+ ]
67
+
68
+ [[package]]
69
+ name = "brotli"
70
+ version = "8.0.4"
71
+ source = "registry+https://github.com/rust-lang/crates.io-index"
72
+ checksum = "5cc91aac060a7a1e25823bdccbfb6af1875b88f17c6daac97894eed8207166b3"
73
+ dependencies = [
74
+ "alloc-no-stdlib",
75
+ "alloc-stdlib",
76
+ "brotli-decompressor",
77
+ ]
78
+
79
+ [[package]]
80
+ name = "brotli-decompressor"
81
+ version = "5.0.3"
82
+ source = "registry+https://github.com/rust-lang/crates.io-index"
83
+ checksum = "3a32acac15fe1967bc3986b2a6347dffc965602354ea6f450ad07e8bfd253583"
84
+ dependencies = [
85
+ "alloc-no-stdlib",
86
+ "alloc-stdlib",
87
+ ]
88
+
89
+ [[package]]
90
+ name = "bytemuck"
91
+ version = "1.25.2"
92
+ source = "registry+https://github.com/rust-lang/crates.io-index"
93
+ checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797"
94
+ dependencies = [
95
+ "bytemuck_derive",
96
+ ]
97
+
98
+ [[package]]
99
+ name = "bytemuck_derive"
100
+ version = "1.12.1"
101
+ source = "registry+https://github.com/rust-lang/crates.io-index"
102
+ checksum = "6a1f896587b6f2c069c73d2f0913e2d590c3990285cd2f0b6aa02b786b4c679c"
103
+ dependencies = [
104
+ "proc-macro2",
105
+ "quote",
106
+ "syn 3.0.9",
107
+ ]
108
+
109
+ [[package]]
110
+ name = "cexpr"
111
+ version = "0.6.0"
112
+ source = "registry+https://github.com/rust-lang/crates.io-index"
113
+ checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
114
+ dependencies = [
115
+ "nom",
116
+ ]
117
+
118
+ [[package]]
119
+ name = "cfg-if"
120
+ version = "1.0.5"
121
+ source = "registry+https://github.com/rust-lang/crates.io-index"
122
+ checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600"
123
+
124
+ [[package]]
125
+ name = "clang-sys"
126
+ version = "1.9.1"
127
+ source = "registry+https://github.com/rust-lang/crates.io-index"
128
+ checksum = "157a8ba7b480713b56f4c09fd13fc3e0a22a5dfab8097ba61cbc5feef950788a"
129
+ dependencies = [
130
+ "glob",
131
+ "libc",
132
+ "libloading",
133
+ ]
134
+
135
+ [[package]]
136
+ name = "cpufeatures"
137
+ version = "0.2.17"
138
+ source = "registry+https://github.com/rust-lang/crates.io-index"
139
+ checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
140
+ dependencies = [
141
+ "libc",
142
+ ]
143
+
144
+ [[package]]
145
+ name = "crypto-common"
146
+ version = "0.1.7"
147
+ source = "registry+https://github.com/rust-lang/crates.io-index"
148
+ checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
149
+ dependencies = [
150
+ "generic-array",
151
+ "typenum",
152
+ ]
153
+
154
+ [[package]]
155
+ name = "digest"
156
+ version = "0.10.7"
157
+ source = "registry+https://github.com/rust-lang/crates.io-index"
158
+ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
159
+ dependencies = [
160
+ "block-buffer",
161
+ "crypto-common",
162
+ ]
163
+
164
+ [[package]]
165
+ name = "either"
166
+ version = "1.19.0"
167
+ source = "registry+https://github.com/rust-lang/crates.io-index"
168
+ checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be"
169
+
170
+ [[package]]
171
+ name = "foldhash"
172
+ version = "0.2.0"
173
+ source = "registry+https://github.com/rust-lang/crates.io-index"
174
+ checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
175
+
176
+ [[package]]
177
+ name = "font-types"
178
+ version = "0.12.7"
179
+ source = "registry+https://github.com/rust-lang/crates.io-index"
180
+ checksum = "835ae9d781464a79026cde387f9cbc650c9a4909d7cf7e658b127e3c35d2f35d"
181
+ dependencies = [
182
+ "bytemuck",
183
+ ]
184
+
185
+ [[package]]
186
+ name = "fontisan"
187
+ version = "0.0.0"
188
+ source = "git+https://github.com/fontist/fontisan-rs?rev=daffb3f45b67517e924a3e5d0e113a2ecbde9959#daffb3f45b67517e924a3e5d0e113a2ecbde9959"
189
+ dependencies = [
190
+ "brotli",
191
+ "brotli-decompressor",
192
+ "miniz_oxide",
193
+ "read-fonts",
194
+ "sha2",
195
+ ]
196
+
197
+ [[package]]
198
+ name = "fontisan_native"
199
+ version = "0.1.0"
200
+ dependencies = [
201
+ "fontisan",
202
+ "magnus",
203
+ "rb-sys",
204
+ ]
205
+
206
+ [[package]]
207
+ name = "generic-array"
208
+ version = "0.14.7"
209
+ source = "registry+https://github.com/rust-lang/crates.io-index"
210
+ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
211
+ dependencies = [
212
+ "typenum",
213
+ "version_check",
214
+ ]
215
+
216
+ [[package]]
217
+ name = "glob"
218
+ version = "0.3.4"
219
+ source = "registry+https://github.com/rust-lang/crates.io-index"
220
+ checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b"
221
+
222
+ [[package]]
223
+ name = "itertools"
224
+ version = "0.13.0"
225
+ source = "registry+https://github.com/rust-lang/crates.io-index"
226
+ checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
227
+ dependencies = [
228
+ "either",
229
+ ]
230
+
231
+ [[package]]
232
+ name = "lazy_static"
233
+ version = "1.5.1"
234
+ source = "registry+https://github.com/rust-lang/crates.io-index"
235
+ checksum = "20870f649af7073d53e38067b2a84312175d56ea15217e1b15bc83506ec50afb"
236
+
237
+ [[package]]
238
+ name = "libc"
239
+ version = "0.2.191"
240
+ source = "registry+https://github.com/rust-lang/crates.io-index"
241
+ checksum = "65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a"
242
+
243
+ [[package]]
244
+ name = "libloading"
245
+ version = "0.8.9"
246
+ source = "registry+https://github.com/rust-lang/crates.io-index"
247
+ checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
248
+ dependencies = [
249
+ "cfg-if",
250
+ "windows-link",
251
+ ]
252
+
253
+ [[package]]
254
+ name = "magnus"
255
+ version = "0.8.4"
256
+ source = "registry+https://github.com/rust-lang/crates.io-index"
257
+ checksum = "e76237a607e1dea288dd0ef0c6c8f49037df2152d14bb52b3542c46522d9e6fc"
258
+ dependencies = [
259
+ "magnus-macros",
260
+ "rb-sys",
261
+ "rb-sys-env",
262
+ "seq-macro",
263
+ ]
264
+
265
+ [[package]]
266
+ name = "magnus-macros"
267
+ version = "0.8.0"
268
+ source = "registry+https://github.com/rust-lang/crates.io-index"
269
+ checksum = "47607461fd8e1513cb4f2076c197d8092d921a1ea75bd08af97398f593751892"
270
+ dependencies = [
271
+ "proc-macro2",
272
+ "quote",
273
+ "syn 2.0.119",
274
+ ]
275
+
276
+ [[package]]
277
+ name = "memchr"
278
+ version = "2.8.3"
279
+ source = "registry+https://github.com/rust-lang/crates.io-index"
280
+ checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
281
+
282
+ [[package]]
283
+ name = "minimal-lexical"
284
+ version = "0.2.1"
285
+ source = "registry+https://github.com/rust-lang/crates.io-index"
286
+ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
287
+
288
+ [[package]]
289
+ name = "miniz_oxide"
290
+ version = "0.8.9"
291
+ source = "registry+https://github.com/rust-lang/crates.io-index"
292
+ checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
293
+ dependencies = [
294
+ "adler2",
295
+ ]
296
+
297
+ [[package]]
298
+ name = "nom"
299
+ version = "7.1.3"
300
+ source = "registry+https://github.com/rust-lang/crates.io-index"
301
+ checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
302
+ dependencies = [
303
+ "memchr",
304
+ "minimal-lexical",
305
+ ]
306
+
307
+ [[package]]
308
+ name = "once_cell"
309
+ version = "1.21.4"
310
+ source = "registry+https://github.com/rust-lang/crates.io-index"
311
+ checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
312
+
313
+ [[package]]
314
+ name = "proc-macro2"
315
+ version = "1.0.107"
316
+ source = "registry+https://github.com/rust-lang/crates.io-index"
317
+ checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
318
+ dependencies = [
319
+ "unicode-ident",
320
+ ]
321
+
322
+ [[package]]
323
+ name = "quote"
324
+ version = "1.0.47"
325
+ source = "registry+https://github.com/rust-lang/crates.io-index"
326
+ checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
327
+ dependencies = [
328
+ "proc-macro2",
329
+ ]
330
+
331
+ [[package]]
332
+ name = "rb-sys"
333
+ version = "0.9.130"
334
+ source = "registry+https://github.com/rust-lang/crates.io-index"
335
+ checksum = "02faf625bb10ba893e3ae620f19c9fb1b5f8fcae0fe4eb86bb3f2230fad75edb"
336
+ dependencies = [
337
+ "rb-sys-build",
338
+ ]
339
+
340
+ [[package]]
341
+ name = "rb-sys-build"
342
+ version = "0.9.130"
343
+ source = "registry+https://github.com/rust-lang/crates.io-index"
344
+ checksum = "05be6f9c86fe5482808162826f6c047d093b3670582296c770de1d94f8066694"
345
+ dependencies = [
346
+ "bindgen",
347
+ "lazy_static",
348
+ "proc-macro2",
349
+ "quote",
350
+ "regex",
351
+ "shell-words",
352
+ "syn 2.0.119",
353
+ ]
354
+
355
+ [[package]]
356
+ name = "rb-sys-env"
357
+ version = "0.2.3"
358
+ source = "registry+https://github.com/rust-lang/crates.io-index"
359
+ checksum = "cca7ad6a7e21e72151d56fe2495a259b5670e204c3adac41ee7ef676ea08117a"
360
+
361
+ [[package]]
362
+ name = "read-fonts"
363
+ version = "0.46.0"
364
+ source = "registry+https://github.com/rust-lang/crates.io-index"
365
+ checksum = "bdaa4fffe9ff3ca2c353fa9729792805b9b3e324695ff5a081f860612e81b330"
366
+ dependencies = [
367
+ "bytemuck",
368
+ "foldhash",
369
+ "font-types",
370
+ "once_cell",
371
+ "smallvec",
372
+ "yoke",
373
+ ]
374
+
375
+ [[package]]
376
+ name = "regex"
377
+ version = "1.13.1"
378
+ source = "registry+https://github.com/rust-lang/crates.io-index"
379
+ checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d"
380
+ dependencies = [
381
+ "aho-corasick",
382
+ "memchr",
383
+ "regex-automata",
384
+ "regex-syntax",
385
+ ]
386
+
387
+ [[package]]
388
+ name = "regex-automata"
389
+ version = "0.4.18"
390
+ source = "registry+https://github.com/rust-lang/crates.io-index"
391
+ checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2"
392
+ dependencies = [
393
+ "aho-corasick",
394
+ "memchr",
395
+ "regex-syntax",
396
+ ]
397
+
398
+ [[package]]
399
+ name = "regex-syntax"
400
+ version = "0.8.11"
401
+ source = "registry+https://github.com/rust-lang/crates.io-index"
402
+ checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
403
+
404
+ [[package]]
405
+ name = "rustc-hash"
406
+ version = "2.1.3"
407
+ source = "registry+https://github.com/rust-lang/crates.io-index"
408
+ checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d"
409
+
410
+ [[package]]
411
+ name = "seq-macro"
412
+ version = "0.3.6"
413
+ source = "registry+https://github.com/rust-lang/crates.io-index"
414
+ checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc"
415
+
416
+ [[package]]
417
+ name = "sha2"
418
+ version = "0.10.9"
419
+ source = "registry+https://github.com/rust-lang/crates.io-index"
420
+ checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
421
+ dependencies = [
422
+ "cfg-if",
423
+ "cpufeatures",
424
+ "digest",
425
+ ]
426
+
427
+ [[package]]
428
+ name = "shell-words"
429
+ version = "1.1.1"
430
+ source = "registry+https://github.com/rust-lang/crates.io-index"
431
+ checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77"
432
+
433
+ [[package]]
434
+ name = "shlex"
435
+ version = "1.3.0"
436
+ source = "registry+https://github.com/rust-lang/crates.io-index"
437
+ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
438
+
439
+ [[package]]
440
+ name = "smallvec"
441
+ version = "1.16.4"
442
+ source = "registry+https://github.com/rust-lang/crates.io-index"
443
+ checksum = "d0d5d4b1981b8bbbb7aed204cae5726d683d5d6ac7e74ec54122ea28f315e7c8"
444
+
445
+ [[package]]
446
+ name = "stable_deref_trait"
447
+ version = "1.2.1"
448
+ source = "registry+https://github.com/rust-lang/crates.io-index"
449
+ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
450
+
451
+ [[package]]
452
+ name = "syn"
453
+ version = "2.0.119"
454
+ source = "registry+https://github.com/rust-lang/crates.io-index"
455
+ checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
456
+ dependencies = [
457
+ "proc-macro2",
458
+ "quote",
459
+ "unicode-ident",
460
+ ]
461
+
462
+ [[package]]
463
+ name = "syn"
464
+ version = "3.0.9"
465
+ source = "registry+https://github.com/rust-lang/crates.io-index"
466
+ checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b"
467
+ dependencies = [
468
+ "proc-macro2",
469
+ "quote",
470
+ "unicode-ident",
471
+ ]
472
+
473
+ [[package]]
474
+ name = "synstructure"
475
+ version = "0.14.0"
476
+ source = "registry+https://github.com/rust-lang/crates.io-index"
477
+ checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02"
478
+ dependencies = [
479
+ "proc-macro2",
480
+ "quote",
481
+ "syn 3.0.9",
482
+ ]
483
+
484
+ [[package]]
485
+ name = "typenum"
486
+ version = "1.20.1"
487
+ source = "registry+https://github.com/rust-lang/crates.io-index"
488
+ checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
489
+
490
+ [[package]]
491
+ name = "unicode-ident"
492
+ version = "1.0.27"
493
+ source = "registry+https://github.com/rust-lang/crates.io-index"
494
+ checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563"
495
+
496
+ [[package]]
497
+ name = "version_check"
498
+ version = "0.9.5"
499
+ source = "registry+https://github.com/rust-lang/crates.io-index"
500
+ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
501
+
502
+ [[package]]
503
+ name = "windows-link"
504
+ version = "0.2.1"
505
+ source = "registry+https://github.com/rust-lang/crates.io-index"
506
+ checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
507
+
508
+ [[package]]
509
+ name = "yoke"
510
+ version = "0.8.4"
511
+ source = "registry+https://github.com/rust-lang/crates.io-index"
512
+ checksum = "417ef3fcf6c300b7dbd25c85531a746931c02ad536f3cf4786ed1e88223340b3"
513
+ dependencies = [
514
+ "stable_deref_trait",
515
+ "yoke-derive",
516
+ "zerofrom",
517
+ ]
518
+
519
+ [[package]]
520
+ name = "yoke-derive"
521
+ version = "0.8.4"
522
+ source = "registry+https://github.com/rust-lang/crates.io-index"
523
+ checksum = "ec8ebde2db3681e8c9980cc27822030e68752690ddfa9473e739aeb4dbde6d71"
524
+ dependencies = [
525
+ "proc-macro2",
526
+ "quote",
527
+ "syn 3.0.9",
528
+ "synstructure",
529
+ ]
530
+
531
+ [[package]]
532
+ name = "zerofrom"
533
+ version = "0.1.8"
534
+ source = "registry+https://github.com/rust-lang/crates.io-index"
535
+ checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272"
536
+ dependencies = [
537
+ "zerofrom-derive",
538
+ ]
539
+
540
+ [[package]]
541
+ name = "zerofrom-derive"
542
+ version = "0.1.8"
543
+ source = "registry+https://github.com/rust-lang/crates.io-index"
544
+ checksum = "f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a"
545
+ dependencies = [
546
+ "proc-macro2",
547
+ "quote",
548
+ "syn 3.0.9",
549
+ "synstructure",
550
+ ]
data/Cargo.toml ADDED
@@ -0,0 +1,12 @@
1
+ # Workspace root for rb-sys (it infers the crate from `cargo metadata` at the gem
2
+ # root). The only member is the :native tier.
3
+ [workspace]
4
+ members = ["ext/fontisan_native"]
5
+ resolver = "2"
6
+
7
+ # A panic must unwind so catch_unwind can turn it into a Ruby error (abort cannot).
8
+ [profile.release]
9
+ panic = "unwind"
10
+
11
+ [profile.dev]
12
+ panic = "unwind"
data/Gemfile CHANGED
@@ -9,6 +9,8 @@ gem "benchmark"
9
9
  # bigdecimal is required by get_process_mem for Ruby 3.4+ compatibility
10
10
  gem "bigdecimal"
11
11
  gem "canon", "~> 0.1.3"
12
+ # Optional runtime dependency of the :ffi engine tier (lib/fontisan/ffi.rb); not in the gemspec.
13
+ gem "ffi"
12
14
  gem "get_process_mem", "~> 0.2"
13
15
  # Octokit provides authenticated GitHub API access for the test-only
14
16
  # fixture downloader (spec/support/fixture_downloader.rb). CI sets
@@ -18,6 +20,7 @@ gem "get_process_mem", "~> 0.2"
18
20
  gem "octokit", group: :test
19
21
  gem "openssl", "~> 3.0"
20
22
  gem "rake"
23
+ gem "rake-compiler"
21
24
  gem "rspec"
22
25
  gem "rubocop"
23
26
  gem "rubocop-performance"
@@ -28,3 +31,10 @@ gem "rubyzip"
28
31
  gem "sys-proctable", platforms: %i[mswin mingw mswin64]
29
32
  # win32ole was a default gem until Ruby 4.0 — pin it for Windows runners
30
33
  gem "win32ole", platforms: %i[mswin mingw mswin64]
34
+
35
+ # Dev-only: the fontist parity spec (spec/corpus/fontist_parity_spec.rb) compares
36
+ # Fontisan::Reference.scan rows with fontist's FontFile/CollectionFile at this ref.
37
+ group :fontist_parity do
38
+ gem "fontist", git: "https://github.com/fontist/fontist.git",
39
+ ref: "85e904c96fff60f60781ae0eb11a8c06e0c73816"
40
+ end