mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-10-31 15:49:36 +00:00
Merge PR #3639: Pair /ActualText correctly past 256 levels of marked content
This commit is contained in:
commit
abef812bfa
2 files changed
+24
-1
No files matched your search
@@ -5218,3 +5218,24 @@ fn a_clipping_copy_on_the_same_baseline_is_refused() {
|
||||
assert!(matches!(&block, Err(EditError::Invalid(m)) if m.contains("clipping path")), "{block:?}");
|
||||
assert_eq!(text::text_lines(&doc, 0).unwrap().len(), 2, "refused means untouched");
|
||||
}
|
||||
|
||||
/// #3573: past the 256-level marked-content cap every `EMC` must still close its own sequence,
|
||||
/// so `/ActualText` nested that deep is neither dropped nor applied to too little text.
|
||||
#[test]
|
||||
fn actual_text_pairs_past_the_marked_content_cap() {
|
||||
let span = "/Span <</ActualText (REPLACED)>> BDC BT /F1 24 Tf 72 700 Td (abc) Tj ET EMC";
|
||||
let outer = "/Span <</ActualText (OUTER)>> BDC BT /F1 24 Tf 72 700 Td /Y BMC (abc) Tj EMC (def) Tj ET EMC";
|
||||
for (content, expected) in [
|
||||
(span.to_string(), "REPLACED"),
|
||||
(format!("{}{span}{}", "/X BMC ".repeat(256), " EMC".repeat(256)), "REPLACED"),
|
||||
(format!("{}{span}{}", "/X BMC ".repeat(1000), " EMC".repeat(1000)), "REPLACED"),
|
||||
(outer.to_string(), "OUTER"),
|
||||
(format!("{}{outer}{}", "/X BMC ".repeat(255), " EMC".repeat(255)), "OUTER"),
|
||||
] {
|
||||
let doc = text_page(&content);
|
||||
let lines = text::text_lines(&doc, 0).unwrap();
|
||||
assert_eq!(lines.iter().map(|l| l.text.as_str()).collect::<Vec<_>>(), [expected]);
|
||||
let reading: Vec<String> = text::reading_blocks(&doc, 0).unwrap().into_iter().map(|b| b.text).collect();
|
||||
assert_eq!(reading, [expected]);
|
||||
}
|
||||
}
|
||||
@@ -829,7 +829,9 @@ fn interpret(
|
||||
let mut actual: Vec<Option<(usize, usize, String)>> = Vec::new();
|
||||
for (i, op) in ops.iter().enumerate() {
|
||||
match op.op.as_slice() {
|
||||
b"BMC" | b"BDC" if marked.len() < 256 => {
|
||||
// No depth cap: every `EMC` pops, so a capped push would pair it with the enclosing
|
||||
// sequence (#3573). Both stacks stay bounded by the number of operators.
|
||||
b"BMC" | b"BDC" => {
|
||||
// Marked text paragraphs/headings are authoritative boundaries. Ignore
|
||||
// artifacts and inner spans, which inherit their enclosing region.
|
||||
let region = matches!(op.name(0), Some(b"P" | b"H" | b"H1" | b"H2" | b"H3" | b"H4" | b"H5" | b"H6" | b"LI" | b"TD" | b"TH"));
|
||||
|
||||
Reference in new issue
Block a user