From 92e8e6eff0d92aa11048a3c86a41a8736e4e1235 Mon Sep 17 00:00:00 2001 From: Grzegorz Martens Date: Mon, 9 Nov 2026 16:48:01 +0100 Subject: [PATCH] M7: Repair Thai maps reads a /CIDToGIDMap given by reference, and takes a missing one as Identity The Consumers review of ba28458ad..b7224cbc9: - `recovered_thai_map` read the descendant's /CIDToGIDMap with `Dict::name`, on the line after e9142b03b's /Encoding check, so a map given by reference made Repair Thai maps pass the font over, and so did a missing one, which is Identity (ISO 32000-2 Table 115), as `composite_glyph_maps`, `LegacyThaiFont` and the renderer read it. It now resolves the map and takes a missing one as Identity. - `MAX_THAI_PROGRAMS` says what it pays for: the programs, and the CMaps and glyph maps read to adapt their cmaps. The metrics read to find and measure the subsets aren't charged to it. Its refusal ("MiB of font data") still says what it counts. Test: `recovered_thai_map_checks_every_kept_glyph_against_the_font_program` recovers the same map with the font's /CIDToGIDMap given by reference and with none. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY --- crates/edit/src/text_regions/styled.rs | 5 +++-- crates/fonts/src/pdf/thai.rs | 22 +++++++++++++++++++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/crates/edit/src/text_regions/styled.rs b/crates/edit/src/text_regions/styled.rs index d45049db02..dbb6c5d46e 100644 --- a/crates/edit/src/text_regions/styled.rs +++ b/crates/edit/src/text_regions/styled.rs @@ -117,8 +117,9 @@ struct LegacyFace { } /// What one edit may decode of its THSarabunPSK subsets' font data: their programs (each at most -/// 16 MiB), which it keeps, and the CMaps and glyph maps their metrics and codes are read from. A -/// page may name many of them. +/// 16 MiB), which it keeps, and the CMaps and glyph maps read to adapt their programs' cmaps. A +/// page may name many of them. The metrics read to find and measure the subsets +/// (`Metrics::from_dict`) aren't charged to it. const MAX_THAI_PROGRAMS: usize = 64 << 20; struct PreparedCharacters { diff --git a/crates/fonts/src/pdf/thai.rs b/crates/fonts/src/pdf/thai.rs index c6e1941fbd..28d29b0055 100644 --- a/crates/fonts/src/pdf/thai.rs +++ b/crates/fonts/src/pdf/thai.rs @@ -24,7 +24,9 @@ pub fn recovered_thai_map(doc: &Document, font: &Dict) -> Option| { + let mut f = font.clone(); + let Some(Object::Array(desc)) = f.get(b"DescendantFonts").cloned() else { panic!("fixture") }; + let Some(Object::Dict(mut desc)) = desc.first().cloned() else { panic!("fixture") }; + match map { + Some(map) => desc.set(b"CIDToGIDMap".to_vec(), map), + None => { + desc.remove(b"CIDToGIDMap"); + } + } + f.set(b"DescendantFonts".to_vec(), Object::Array(vec![Object::Dict(desc)])); + f + }; + let by_reference = with_map(Some(Object::Ref(doc.add(Object::name("Identity"))))); + assert_eq!(recovered_thai_map(&doc, &by_reference), recovered_thai_map(&doc, &font), "a map by reference"); + assert_eq!(recovered_thai_map(&doc, &with_map(None)), recovered_thai_map(&doc, &font), "a missing map"); // 259–261 are ฮ, ฯ and ะ, between the last anchor (อ, 258) and the first mark: a font that // put Mai Han-akat one glyph earlier passes every anchor and only this check sees it. let mut shifted = thai_ordered_program();