From ffd831761e9639a2d61369130f6fbe44754afa3f Mon Sep 17 00:00:00 2001 From: NetterSilver <133535268+Silvertree2010@users.noreply.github.com> Date: Fri, 23 Oct 2026 02:41:42 +0200 Subject: [PATCH] Cap the face count of a font collection in enumerate_faces Fixes #3596 Co-Authored-By: Claude Haiku 5.5 Co-Authored-By: Claude Sonnet 5.5 --- crates/text/src/fontdb.rs | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/crates/text/src/fontdb.rs b/crates/text/src/fontdb.rs index 3d97083a3..5cba7fb21 100644 --- a/crates/text/src/fontdb.rs +++ b/crates/text/src/fontdb.rs @@ -1079,12 +1079,15 @@ fn named_instances( (out, renamed) } +/// The most faces read from a (possibly damaged) collection. +const MAX_FACES: u32 = 256; + /// Parse every face in `data` (a font file or collection) and the named instances of its variable /// ones. Returns each style with the index of its face. fn enumerate_faces(data: &[u8]) -> Vec<(u32, FaceStyle)> { let count = match FileRef::new(data) { Ok(FileRef::Font(_)) => 1, - Ok(FileRef::Collection(c)) => c.len(), + Ok(FileRef::Collection(c)) => c.len().min(MAX_FACES), Err(_) => 0, }; (0..count) @@ -1115,8 +1118,6 @@ const OUTLINE_TABLES: [&[u8; 4]; 6] = [b"glyf", b"CFF ", b"CFF2", b"VARC", b"sbi /// are left out. #[cfg(not(target_arch = "wasm32"))] fn file_face_names(path: &Path) -> Vec { - /// The most faces read from a (possibly damaged) collection. - const MAX_FACES: u32 = 256; file_face_names_within(path, MAX_FACES, u64::MAX) } @@ -2584,6 +2585,26 @@ mod alias_tests { font } + #[test] + fn a_collection_lists_at_most_max_faces() { + let mut font = name_font(&[(3, 0x0409, 1, "Fam"), (3, 0x0409, 2, "Regular")]); + let n = 1000u32; + let base = 12 + 4 * n; + let table = u32::from_be_bytes(font[20..24].try_into().unwrap()) + base; + font[20..24].copy_from_slice(&table.to_be_bytes()); + let mut ttc = b"ttcf".to_vec(); + for v in [0x0001_0000, n] { + ttc.extend_from_slice(&u32::to_be_bytes(v)); + } + for _ in 0..n { + ttc.extend_from_slice(&base.to_be_bytes()); + } + ttc.extend(font); + let faces = enumerate_faces(&ttc); + assert!(!faces.is_empty()); + assert!(faces.len() <= MAX_FACES as usize, "{} faces", faces.len()); + } + fn keys(records: &[(u16, u16, u16, &str)]) -> (String, String, FaceKeys) { let font = name_font(records); let f = skrifa::FontRef::new(&font).unwrap();