mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-10 13:01:29 +00:00
Preserve action chains when discarding external references
This commit is contained in:
1 parent
c3749e6a98
commit
3ef82b55eb
2 files changed
+47
-5
No files matched your search
@@ -219,7 +219,7 @@ impl Walk {
|
||||
match rest {
|
||||
Some(Kept::Now(v)) => {
|
||||
let mut d = d.clone();
|
||||
set_next(&mut d, v);
|
||||
set_next(doc, &mut d, v);
|
||||
Kept::Now(vec![Object::Dict(d)])
|
||||
}
|
||||
_ => Kept::Same,
|
||||
@@ -230,13 +230,16 @@ impl Walk {
|
||||
}
|
||||
}
|
||||
|
||||
fn set_next(d: &mut Dict, mut v: Vec<Object>) {
|
||||
fn set_next(doc: &mut Document, d: &mut Dict, mut v: Vec<Object>) {
|
||||
match v.len() {
|
||||
0 => {
|
||||
d.remove(b"Next");
|
||||
}
|
||||
1 => d.set(b"Next".to_vec(), v.remove(0)),
|
||||
_ => d.set(b"Next".to_vec(), Object::Array(v)),
|
||||
_ => {
|
||||
let next = v.into_iter().map(|a| if matches!(a, Object::Dict(_) | Object::Array(_)) { Object::Ref(doc.add(a)) } else { a }).collect();
|
||||
d.set(b"Next".to_vec(), Object::Array(next));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,8 +281,8 @@ fn strip_action(doc: &mut Document, a: &Object, owner: ObjRef) -> Result<Option<
|
||||
let Some(mut d) = doc.resolve(&first).as_dict().cloned() else { return Ok(Some(None)) };
|
||||
let mut next = d.get(b"Next").map(|n| listed(doc, n)).unwrap_or_default();
|
||||
next.extend(v);
|
||||
set_next(&mut d, next);
|
||||
Ok(Some(Some(Object::Dict(d))))
|
||||
set_next(doc, &mut d, next);
|
||||
Ok(Some(Some(Object::Ref(doc.add(Object::Dict(d))))))
|
||||
}
|
||||
|
||||
/// The outline walk: bookmarks stored as their own objects wait on `stack`; those stored inside
|
||||
|
||||
@@ -2569,6 +2569,20 @@ fn links_and_bookmarks_to_other_documents_are_discarded_and_links_within_stay()
|
||||
assert_eq!(chain(&doc, bookmark(&doc, items[1]).get(b"A").unwrap()), ["Named"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn discarding_a_remote_action_keeps_the_links_local_destination() {
|
||||
let (mut doc, p, _) =
|
||||
linked_doc(|_, p| vec![link_with(Some(action("GoToR", None)), Some(Object::Array(vec![Object::Ref(p), Object::name("Fit")])))], &[]);
|
||||
let report = optimize(&mut doc, &Settings { discard_external_refs: true, ..Settings::default() }).unwrap();
|
||||
assert_eq!(report.external_links, 1);
|
||||
let bytes = write_full(&doc, &SaveOptions::default()).unwrap();
|
||||
let reopened = Document::open(Arc::new(bytes)).unwrap();
|
||||
let links = annots_of(&reopened, p);
|
||||
assert_eq!(links.len(), 1);
|
||||
assert!(links[0].get(b"A").is_none());
|
||||
assert_eq!(links[0].get(b"Dest"), Some(&Object::Array(vec![Object::Ref(p), Object::name("Fit")])));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn repeated_indirect_remote_link_is_removed_from_one_page() {
|
||||
let (mut doc, p, _) = linked_doc(
|
||||
@@ -2709,6 +2723,31 @@ fn a_long_chain_of_indirect_actions_stays_indirect_and_reads_back_after_saving()
|
||||
assert_eq!(chain(&reopened, &a), vec!["URI"; 130], "every web link reads back");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn promoted_action_chains_read_back_after_saving() {
|
||||
let (doc, p, _) = linked_doc(
|
||||
|doc, _| {
|
||||
let tail = (0..126).fold(action("Named", None), |next, _| action("Named", Some(next)));
|
||||
let first = doc.add(tail);
|
||||
let next = Object::Array(vec![Object::Ref(first), action("URI", None)]);
|
||||
let link = doc.add(link_with(Some(action("GoToR", Some(next))), None));
|
||||
vec![Object::Ref(link)]
|
||||
},
|
||||
&[],
|
||||
);
|
||||
let bytes = write_full(&doc, &SaveOptions::default()).unwrap();
|
||||
let mut doc = Document::open(Arc::new(bytes)).unwrap();
|
||||
let original = annots_of(&doc, p)[0].get(b"A").cloned().unwrap();
|
||||
assert_eq!(chain(&doc, &original).len(), 129);
|
||||
let report = optimize(&mut doc, &Settings { discard_external_refs: true, ..Settings::default() }).unwrap();
|
||||
assert_eq!(report.external_links, 1);
|
||||
let bytes = write_full(&doc, &SaveOptions::default()).unwrap();
|
||||
let reopened = Document::open(Arc::new(bytes)).unwrap();
|
||||
let a = annots_of(&reopened, p)[0].get(b"A").cloned().unwrap();
|
||||
let expected: Vec<_> = std::iter::repeat_n("Named".to_string(), 127).chain(["URI".to_string()]).collect();
|
||||
assert_eq!(chain(&reopened, &a), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shared_actions_that_multiply_stop_the_optimization_when_one_opens_another_document() {
|
||||
use pdfcraft_optimize::OptimizeError;
|
||||
|
||||
Reference in new issue
Block a user