From 44fea82aaad92856917b6475b0ce9a3777f2e465 Mon Sep 17 00:00:00 2001 From: Simon Gardling Date: Fri, 5 Dec 2025 14:02:13 -0500 Subject: [PATCH] font subsetting: pyftsubset -> allsorts --- Cargo.lock | 337 +++++++++++++++++++++++++++++++++++++++-------------- Cargo.toml | 2 +- build.rs | 92 +++++++-------- flake.nix | 1 - 4 files changed, 297 insertions(+), 135 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6656d77..e43020d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -66,6 +66,56 @@ dependencies = [ "memchr", ] +[[package]] +name = "aliasable" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "allsorts" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ec6442ceba5ea9d0201cd0afe96ecac4e8253e5f5be725e074747e6f4238735" +dependencies = [ + "bitflags 1.3.2", + "bitreader", + "brotli-decompressor", + "byteorder", + "crc32fast", + "encoding_rs", + "flate2", + "glyph-names", + "itertools 0.10.5", + "lazy_static", + "libc", + "log", + "num-traits", + "ouroboros", + "pathfinder_geometry", + "rustc-hash 1.1.0", + "tinyvec", + "ucd-trie", + "unicode-canonical-combining-class", + "unicode-general-category", + "unicode-joining-type", +] + [[package]] name = "android-activity" version = "0.6.0" @@ -217,6 +267,15 @@ version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +[[package]] +name = "bitreader" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "886559b1e163d56c765bc3a985febb4eee8009f625244511d8ee3c432e08c066" +dependencies = [ + "cfg-if", +] + [[package]] name = "block2" version = "0.5.1" @@ -226,6 +285,16 @@ dependencies = [ "objc2 0.5.2", ] +[[package]] +name = "brotli-decompressor" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a334ef7c9e23abf0ce748e8cd309037da93e606ad52eb372e4ce327a0dcfbdfd" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + [[package]] name = "bumpalo" version = "3.19.0" @@ -249,9 +318,15 @@ checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "byteorder-lite" version = "0.1.0" @@ -632,7 +707,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -665,12 +740,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" -[[package]] -name = "dunce" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" - [[package]] name = "ecolor" version = "0.33.2" @@ -814,6 +883,15 @@ dependencies = [ "serde", ] +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + [[package]] name = "enumn" version = "0.1.14" @@ -822,7 +900,7 @@ checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -899,7 +977,7 @@ checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -931,11 +1009,12 @@ dependencies = [ [[package]] name = "flate2" -version = "1.1.5" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", + "libz-sys", "miniz_oxide", ] @@ -963,7 +1042,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -981,16 +1060,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "fsio" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4944f16eb6a05b4b2b79986b4786867bb275f52882adea798f17cc2588f25b2" -dependencies = [ - "dunce", - "rand", -] - [[package]] name = "gethostname" version = "1.1.0" @@ -1109,6 +1178,12 @@ dependencies = [ "gl_generator", ] +[[package]] +name = "glyph-names" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3531d702d6c1a3ba92a5fb55a404c7b8c476c8e7ca249951077afcbe4bc807f" + [[package]] name = "half" version = "1.8.3" @@ -1136,6 +1211,12 @@ dependencies = [ "foldhash", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -1704,7 +1785,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -2017,6 +2098,30 @@ dependencies = [ "libredox", ] +[[package]] +name = "ouroboros" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2ba07320d39dfea882faa70554b4bd342a5f273ed59ba7c1c6b4c840492c954" +dependencies = [ + "aliasable", + "ouroboros_macro", + "static_assertions", +] + +[[package]] +name = "ouroboros_macro" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec4c6225c69b4ca778c0aea097321a64c421cf4577b331c61b229267edabb6f8" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "owned_ttf_parser" version = "0.25.1" @@ -2058,6 +2163,25 @@ dependencies = [ "phf_codegen", ] +[[package]] +name = "pathfinder_geometry" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b7e7b4ea703700ce73ebf128e1450eb69c3a8329199ffbfb9b2a0418e5ad3" +dependencies = [ + "log", + "pathfinder_simd", +] + +[[package]] +name = "pathfinder_simd" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf9027960355bf3afff9841918474a81a5f972ac6d226d518060bba758b5ad57" +dependencies = [ + "rustc_version", +] + [[package]] name = "percent-encoding" version = "2.3.2" @@ -2120,7 +2244,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -2241,15 +2365,6 @@ dependencies = [ "thiserror 1.0.69", ] -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] - [[package]] name = "proc-macro-crate" version = "3.4.0" @@ -2259,6 +2374,30 @@ dependencies = [ "toml_edit", ] +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.103" @@ -2322,35 +2461,6 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" -[[package]] -name = "rand" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" -dependencies = [ - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" -dependencies = [ - "getrandom", -] - [[package]] name = "raw-window-handle" version = "0.6.2" @@ -2439,15 +2549,6 @@ dependencies = [ "bytemuck", ] -[[package]] -name = "run_script" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8f982753d06bafa2d1e5c1bd5be496bcb3cd02919a89f07e7f21c7a6ecb4e1a" -dependencies = [ - "fsio", -] - [[package]] name = "rustc-demangle" version = "0.1.26" @@ -2466,6 +2567,15 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.38.44" @@ -2534,6 +2644,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + [[package]] name = "serde" version = "1.0.228" @@ -2571,7 +2687,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -2770,6 +2886,16 @@ dependencies = [ "symbolic-common", ] +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.111" @@ -2789,7 +2915,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -2840,7 +2966,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -2851,7 +2977,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -2930,6 +3056,21 @@ dependencies = [ "serde_json", ] +[[package]] +name = "tinyvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "toml_datetime" version = "0.7.3" @@ -2980,7 +3121,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -3076,12 +3217,36 @@ dependencies = [ "tz-rs", ] +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[package]] +name = "unicode-canonical-combining-class" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6925586af9268182c711e47c0853ed84131049efaca41776d0ca97f983865c32" + +[[package]] +name = "unicode-general-category" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2281c8c1d221438e373249e065ca4989c4c36952c211ff21a0ee91c44a3869e7" + [[package]] name = "unicode-ident" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +[[package]] +name = "unicode-joining-type" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22f8cb47ccb8bc750808755af3071da4a10dcd147b68fc874b7ae4b12543f6f5" + [[package]] name = "unicode-segmentation" version = "1.12.0" @@ -3190,7 +3355,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn", + "syn 2.0.111", "wasm-bindgen-shared", ] @@ -3225,7 +3390,7 @@ checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3564,7 +3729,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -3575,7 +3740,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -3968,7 +4133,7 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", "synstructure", ] @@ -3976,6 +4141,7 @@ dependencies = [ name = "ytbn_graphing_software" version = "0.1.0" dependencies = [ + "allsorts", "base64", "benchmarks", "bincode", @@ -3988,7 +4154,6 @@ dependencies = [ "itertools 0.14.0", "lol_alloc", "parsing", - "run_script", "ruzstd", "serde", "serde_json", @@ -4020,7 +4185,7 @@ checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -4040,7 +4205,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", "synstructure", ] @@ -4074,7 +4239,7 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 54675ba..f67c3af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -72,8 +72,8 @@ bincode = "1.3" serde = "1" serde_json = "1" zstd = { version = "0.13", default-features = false, features = ["pkg-config"] } -run_script = "0.11" itertools = "0.14" +allsorts = "0.15" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] tracing-subscriber = "0.3" diff --git a/build.rs b/build.rs index dfd5aac..58c5e7b 100644 --- a/build.rs +++ b/build.rs @@ -1,8 +1,14 @@ -use epaint::{ - FontFamily, - text::{FontData, FontDefinitions, FontTweak}, +use allsorts::{ + binary::read::ReadScope, + font::{Font, MatchingPresentation}, + font_data::FontData as AllsortsFontData, + subset::subset, + tag, +}; +use epaint::{ + text::{FontData, FontDefinitions, FontTweak}, + FontFamily, }; -use run_script::ScriptOptions; use std::{ collections::BTreeMap, env, @@ -18,52 +24,44 @@ include!(concat!( )); fn font_stripper(from: &str, out: &str, unicodes: Vec) -> Result, String> { - let unicodes: Vec = unicodes.iter().map(|c| to_unicode_hash(*c)).collect(); + let font_path = format!("{}/assets/{}", env!("CARGO_MANIFEST_DIR"), from); + let font_data = std::fs::read(&font_path).map_err(|e| e.to_string())?; + let scope = ReadScope::new(&font_data); + let font_file = scope + .read::() + .map_err(|e| format!("Failed to read font data: {}", e))?; + let provider = font_file + .table_provider(0) + .map_err(|e| format!("Failed to get table provider: {}", e))?; + let mut font = Font::new(provider).map_err(|e| format!("Failed to create font: {:?}", e))?; + + let mut glyph_ids = Vec::new(); + for &ch in &unicodes { + let mut glyph_ids_curr = font + .map_glyphs( + &ch.to_string(), + tag::LATN, + MatchingPresentation::NotRequired, + ) + .into_iter() + .map(|glyph| glyph.glyph_index) + .collect(); + + glyph_ids.append(&mut glyph_ids_curr); + } + // Include .notdef glyph + glyph_ids.push(0); + glyph_ids.sort(); + glyph_ids.dedup(); + + let subset_data = subset(&font.font_table_provider, &glyph_ids) + .map_err(|e| format!("Failed to subset font: {}", e))?; let new_path = [&env::var("OUT_DIR").unwrap(), out].concat(); - let unicodes_formatted = unicodes - .iter() - .map(|u| format!("U+{}", u)) - .collect::>() - .join(","); + std::fs::write(&new_path, &subset_data) + .map_err(|e| format!("Failed to write subset font: {}", e))?; - // Test to see if pyftsubset is found - let pyftsubset_detect = run_script::run("whereis pyftsubset", &(vec![]), &ScriptOptions::new()); - match pyftsubset_detect { - Ok((_i, s1, _s2)) => { - if s1 == "pyftsubset: " { - return Err(String::from("pyftsubset not found")); - } - } - // It was not, return an error and abort - Err(x) => return Err(x.to_string()), - } - - let script_result = run_script::run( - &format!( - "pyftsubset {}/assets/{} --unicodes={} - mv {}/assets/{} {}", - env!("CARGO_MANIFEST_DIR"), - from, - unicodes_formatted, - env!("CARGO_MANIFEST_DIR"), - from.replace(".ttf", ".subset.ttf"), - new_path - ), - &(vec![]), - &ScriptOptions::new(), - ); - - if let Ok((_, _, error)) = script_result { - if error.is_empty() { - return Ok(std::fs::read(new_path).unwrap()); - } else { - return Err(error); - } - } else if let Err(error) = script_result { - return Err(error.to_string()); - } - unreachable!() + Ok(subset_data) } fn main() { diff --git a/flake.nix b/flake.nix index 33b8be4..d67a76e 100644 --- a/flake.nix +++ b/flake.nix @@ -169,7 +169,6 @@ rustToolchain wasm-bindgen-cli binaryen - python3Packages.fonttools rust-analyzer pkg-config clang