mirror of
https://github.com/storytold/figcraft.git
synced 2026-10-27 11:56:50 -06:00
M7: font manager scan: drain Core Text's autoreleased objects; core-text 22
Review on #1309 pointed out that core-text 20.1's get_descriptors retains the array it gets under the create rule a second time, so every scan kept one array of font descriptors alive. Checking that turned up a larger leak: Core Text autoreleases objects while it builds the collection, and the scan runs where no autorelease pool is active (the app's background scan thread, the CLI, the MCP server), so nothing ever drained them. Measured with `figcraft-cli run` of N `text.rescanFonts` steps on macOS 15 (peak memory footprint): | | 10 rescans | 200 rescans | |---|---|---| | main, without this PR | 221 MB | 220 MB | | this PR before the fix | 228 MB | 796 MB | | with the fix | 226 MB | 225 MB | A standalone Swift loop over the same Core Text calls grows from 9 MB to 759 MB over 200 scans without a pool and stays at 20 MB inside one, so the pool is what matters; the core-text bump removes the over-retain on top. - The query runs inside objc2::rc::autoreleasepool. objc2 0.6 is already in the lockfile (winit's), and the function is safe, so the workspace's unsafe_code = "forbid" still holds. - core-text goes to =22.0.0, the first release that takes ownership of the array correctly. It brings core-foundation 0.10, core-graphics 0.25 and core-graphics-types 0.2 beside the older versions other crates use. 22.0 moved framework linking behind a `link` feature that is on by default, so with default features off it is named explicitly. A rescan takes about 0.2 s instead of 0.08 s on that Mac (266 more font files are indexed); it only runs when asked for. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
5699e7abe6
commit
7f6a3a4e46
Generated
+32
-8
@@ -855,7 +855,20 @@ checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"core-foundation 0.9.4",
|
||||
"core-graphics-types",
|
||||
"core-graphics-types 0.1.3",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-graphics"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97"
|
||||
dependencies = [
|
||||
"bitflags 2.13.2",
|
||||
"core-foundation 0.10.1",
|
||||
"core-graphics-types 0.2.0",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
]
|
||||
@@ -872,17 +885,27 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-text"
|
||||
version = "20.1.0"
|
||||
name = "core-graphics-types"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9d2790b5c08465d49f8dc05c8bcae9fea467855947db39b0f8145c091aaced5"
|
||||
checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb"
|
||||
dependencies = [
|
||||
"core-foundation",
|
||||
"core-graphics",
|
||||
"foreign-types",
|
||||
"bitflags 2.13.2",
|
||||
"core-foundation 0.10.1",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-text"
|
||||
version = "22.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "333dab512ce710ca2d08574c373d246dbeac8b22769e47da4c0e72730ce442b7"
|
||||
dependencies = [
|
||||
"core-foundation 0.10.1",
|
||||
"core-graphics 0.25.0",
|
||||
"foreign-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core_detect"
|
||||
version = "1.0.0"
|
||||
@@ -1796,6 +1819,7 @@ dependencies = [
|
||||
"figcraft-geom",
|
||||
"harfrust 0.13.3",
|
||||
"log",
|
||||
"objc2 0.6.5",
|
||||
"png",
|
||||
"skrifa 0.47.0",
|
||||
"unicode-bidi",
|
||||
@@ -5992,7 +6016,7 @@ dependencies = [
|
||||
"cfg_aliases",
|
||||
"concurrent-queue",
|
||||
"core-foundation 0.9.4",
|
||||
"core-graphics",
|
||||
"core-graphics 0.23.2",
|
||||
"cursor-icon",
|
||||
"dpi",
|
||||
"js-sys",
|
||||
|
||||
@@ -21,8 +21,10 @@ log = { workspace = true }
|
||||
|
||||
# Fonts that font managers (RightFont, FontBase, Typeface) activate without copying them into a font
|
||||
# folder are known only to Core Text. Its safe wrappers list every available font's file (Core Text
|
||||
# needs unsafe FFI, which the workspace forbids). Its dependencies (core-foundation 0.9,
|
||||
# core-graphics 0.23, foreign-types 0.5, libc) are already in the lockfile. Pinned exactly: review
|
||||
# the diff before bumping.
|
||||
# needs unsafe FFI, which the workspace forbids). 22.0 is the first release whose
|
||||
# `get_descriptors` takes ownership of the array correctly (20.x and 21.x leak it on every scan);
|
||||
# it brings core-foundation 0.10, core-graphics 0.25 and core-graphics-types 0.2 beside the older
|
||||
# versions other crates use. Pinned exactly: review the diff before bumping.
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
core-text = { version = "=20.1.0", default-features = false }
|
||||
core-text = { version = "=22.0.0", default-features = false, features = ["link"] }
|
||||
objc2 = "0.6"
|
||||
|
||||
@@ -850,10 +850,12 @@ fn files_outside_dirs(files: Vec<std::path::PathBuf>, dirs: &[std::path::PathBuf
|
||||
#[cfg(target_os = "macos")]
|
||||
fn font_manager_files() -> Vec<std::path::PathBuf> {
|
||||
std::panic::catch_unwind(|| {
|
||||
core_text::font_collection::create_for_all_families()
|
||||
.get_descriptors()
|
||||
.map(|descriptors| descriptors.iter().filter_map(|descriptor| descriptor.font_path()).collect())
|
||||
.unwrap_or_default()
|
||||
objc2::rc::autoreleasepool(|_| {
|
||||
core_text::font_collection::create_for_all_families()
|
||||
.get_descriptors()
|
||||
.map(|descriptors| descriptors.iter().filter_map(|descriptor| descriptor.font_path()).collect())
|
||||
.unwrap_or_default()
|
||||
})
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user