From b88c8d79abd4496fb588544f25a26ed37eaa28ea Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 19 Oct 2026 18:07:05 +0000 Subject: [PATCH] M2: the two Identity-H ToUnicode rules point at each other Review follow-up on #3497: the editing map in crates/fonts and the vendored renderer each read an identity /ToUnicode name as code = Unicode without controls or lone surrogates; each now names the other, so a change to one is made to both. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01LymhVaGZCWwB9HNEbLzeMM --- crates/fonts/src/pdf.rs | 4 +++- vendor/hayro-interpret/src/font/cid.rs | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/crates/fonts/src/pdf.rs b/crates/fonts/src/pdf.rs index 6197d8e5c8..fe2a8a9057 100644 --- a/crates/fonts/src/pdf.rs +++ b/crates/fonts/src/pdf.rs @@ -1216,7 +1216,9 @@ fn unicode_map(doc: &Document, font: &Dict, composite: bool) -> Unicode { // `/ToUnicode /Identity-H` is not a stream, as ISO 32000-2 ยง9.10.3 requires, but CAD // exporters (WSCAD among them) write it for composite fonts whose two-byte codes are the // UTF-16 code units. Acrobat shows them as code = Unicode, and so does the renderer's - // text layer; without it the text could be seen but not edited or found. + // text layer; without it the text could be seen but not edited or found. The same rule + // (code = Unicode, no controls or lone surrogates) is in the vendored renderer, + // `Type0Font::char_code_to_unicode` in vendor/hayro-interpret/src/font/cid.rs: keep both alike. Some(Object::Name(n)) if composite && matches!(n.as_slice(), b"Identity-H" | b"Identity-V") => { parse_to_unicode(&identity_to_unicode(), &mut out); } diff --git a/vendor/hayro-interpret/src/font/cid.rs b/vendor/hayro-interpret/src/font/cid.rs index 426c3c34c5..1451359252 100644 --- a/vendor/hayro-interpret/src/font/cid.rs +++ b/vendor/hayro-interpret/src/font/cid.rs @@ -445,7 +445,8 @@ impl Type0Font { /// identity `/ToUnicode` name, when the code is a control or a lone surrogate). pub(crate) fn char_code_to_unicode(&self, code: u32) -> Option { if self.identity_to_unicode { - // Controls and lone surrogates are not text. + // Controls and lone surrogates are not text. The same rule builds the editing + // map, `identity_to_unicode` in crates/fonts/src/pdf.rs: keep both alike. return char::from_u32(code) .filter(|c| !c.is_control()) .map(BfString::Char);