fix(audit): an identity cm between re and fill no longer hides a cover (#1333) (#1410)

Co-authored-by: umesh429 <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
This commit is contained in:
authored and GitHub committed 2026-10-12 07:54:52 -04:00
1 parent 77c3f2003a
commit a9a8ac63b7
2 files changed
+20 -1

No files matched your search

+6 -1
View File
@@ -98,12 +98,17 @@ impl<'a> Walker<'a> {
pending = None;
}
b"cm" => {
let before = gs.ctm;
if let Some(m) = Matrix::from_operands(&op.operands)
&& m.0.iter().all(|v| v.is_finite())
{
gs.ctm = m.then(&gs.ctm);
}
pending = None;
// A `cm` that leaves the CTM unchanged (an identity matrix) cannot move the
// pending rectangle, so keep it for the fill (#1333).
if gs.ctm != before {
pending = None;
}
}
b"g" => {
if let Some(v) = op.num(0).filter(|v| v.is_finite()) {
+14
View File
@@ -113,6 +113,20 @@ fn faux_redaction_is_found() {
assert!(f.covered_text.contains("SECRET"), "covered_text was {:?}", f.covered_text);
}
#[test]
fn identity_matrix_between_rectangle_and_fill_still_covers_text() {
// A no-op `cm` inside the path must not drop the pending rectangle (#1333).
for cover in [&b"0 g\n100 688 220 32 re 1 0 0 1 0 0 cm f\n"[..], b"0 g\n1 0 0 1 0 0 cm 100 688 220 32 re f\n"] {
let mut content = b"BT /F1 24 Tf 100 700 Td (SECRET DATA 123) Tj ET\n".to_vec();
content.extend_from_slice(cover);
let findings = audit_redactions(&open(one_page(&content, ""))).expect("audit must run");
assert_eq!(findings.len(), 1, "{:?}: {findings:?}", String::from_utf8_lossy(cover));
assert_eq!(findings[0].kind, FindingKind::CoveredText);
assert_eq!(findings[0].rect, [100.0, 688.0, 320.0, 720.0]);
assert_eq!(findings[0].covered_text, "SECRET DATA 123");
}
}
#[test]
fn clean_document_has_no_findings() {
let content = b"BT /F1 24 Tf 100 700 Td (nothing hidden here) Tj ET\n";