mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-11 16:36:13 -06:00
Merge origin/main into merge/preflight-pdfa-checks
This commit is contained in:
@@ -763,8 +763,9 @@ pub(crate) fn same_pages(a: &[pdfcraft_render::PageInfo], b: &[pdfcraft_render::
|
||||
}
|
||||
|
||||
/// Each document-information field of `info` with its value in `cos` (`/Info`, else XMP), read
|
||||
/// the way the full inspection reads them: NULs and spaces trimmed, empty is none.
|
||||
pub(crate) fn info_fields<'a>(info: &'a mut DocInfo, cos: &pdfcraft_cos::Document) -> [(&'a mut Option<String>, Option<String>); 6] {
|
||||
/// the way the full inspection reads them: NULs and spaces trimmed, empty is none, dates shown as
|
||||
/// [`pdfcraft_render::pretty_date`] shows them.
|
||||
pub(crate) fn info_fields<'a>(info: &'a mut DocInfo, cos: &pdfcraft_cos::Document) -> [(&'a mut Option<String>, Option<String>); 8] {
|
||||
let read = |key| pdfcraft_organize::info(cos, key).map(|v| v.trim_matches('\0').trim().to_string()).filter(|v| !v.is_empty());
|
||||
[
|
||||
(&mut info.title, read("Title")),
|
||||
@@ -773,6 +774,8 @@ pub(crate) fn info_fields<'a>(info: &'a mut DocInfo, cos: &pdfcraft_cos::Documen
|
||||
(&mut info.keywords, read("Keywords")),
|
||||
(&mut info.creator, read("Creator")),
|
||||
(&mut info.producer, read("Producer")),
|
||||
(&mut info.created, read("CreationDate").map(|d| pdfcraft_render::pretty_date(&d))),
|
||||
(&mut info.modified, read("ModDate").map(|d| pdfcraft_render::pretty_date(&d))),
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ pub use pdfcraft_fonts::{MAX_SIGNATURE_CHARS, ScriptOutline, script_missing, scr
|
||||
|
||||
/// Comment geometry helpers (text-box line breaking) for frontends.
|
||||
pub use pdfcraft_annot::appearance as annot_text;
|
||||
pub use pdfcraft_annot::links::{Highlight as LinkHighlight, LinkAction, LinkItem, LinkStyle};
|
||||
pub use pdfcraft_annot::links::{Highlight as LinkHighlight, LinkAction, LinkItem, LinkStyle, LinkZoom};
|
||||
pub use pdfcraft_annot::{
|
||||
Activation3d, AppearanceCache, AttachIcon, BorderShape, FillMark, LineEnding, Markup, NOTE_SIZE, NewAnnotation, NoteIcon, OverlayFont,
|
||||
OverlayLook, Props as CommentProps, ReviewState, Rgb, Shape, StampGroup, StampKind, Style, rect_quad,
|
||||
|
||||
@@ -4887,6 +4887,25 @@ fn split_by_size_and_bookmarks_and_page_filters() {
|
||||
assert_eq!(filter_pages(info, &all, PageParity::Odd, PageOrientation::Portrait), [0, 2, 4]);
|
||||
}
|
||||
|
||||
/// A zoomed link follows its target page, not its number: deleting a page before the target keeps
|
||||
/// the link on that page at its zoom. Deleting the target page drops the link's destination, as
|
||||
/// for any link to a deleted page, and undo brings it back with its zoom.
|
||||
#[test]
|
||||
fn a_zoomed_link_follows_its_page_and_loses_it_when_the_page_is_deleted() {
|
||||
let (mut s, id) = session_with(3);
|
||||
let zoom = LinkZoom::Percent(200.0);
|
||||
let rect = [10.0, 10.0, 60.0, 30.0];
|
||||
s.apply(id, Edit::AddLink { page: 0, rect, action: LinkAction::Page { page: 2, zoom }, style: LinkStyle::default() }).unwrap();
|
||||
let action = |s: &Session| s.get(id).unwrap().links()[0].action.clone();
|
||||
s.apply(id, Edit::DeletePages { pages: vec![1] }).unwrap();
|
||||
assert_eq!(action(&s), LinkAction::Page { page: 1, zoom }, "the link follows its page");
|
||||
s.apply(id, Edit::DeletePages { pages: vec![1] }).unwrap();
|
||||
// The destination is removed, not left pointing at a page that is gone.
|
||||
assert_eq!(action(&s), LinkAction::Other("no action".into()), "no destination left");
|
||||
s.undo(id).unwrap();
|
||||
assert_eq!(action(&s), LinkAction::Page { page: 1, zoom }, "undo restores the destination and its zoom");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn links_from_urls_and_link_edits() {
|
||||
// One page whose text contains a web address.
|
||||
@@ -4928,8 +4947,12 @@ fn links_from_urls_and_link_edits() {
|
||||
assert_eq!(s.get(id).unwrap().links().len(), 1);
|
||||
// Link Properties and delete.
|
||||
let l = s.get(id).unwrap().links()[0].clone();
|
||||
s.apply(id, Edit::SetLink { page: 0, index: l.index, rect: None, action: Some(LinkAction::Page(0)), style: None }).unwrap();
|
||||
assert_eq!(s.get(id).unwrap().links()[0].action, LinkAction::Page(0));
|
||||
s.apply(
|
||||
id,
|
||||
Edit::SetLink { page: 0, index: l.index, rect: None, action: Some(LinkAction::Page { page: 0, zoom: LinkZoom::FitPage }), style: None },
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(s.get(id).unwrap().links()[0].action, LinkAction::Page { page: 0, zoom: LinkZoom::FitPage });
|
||||
s.apply(id, Edit::DeleteLink { page: 0, index: l.index }).unwrap();
|
||||
assert!(s.get(id).unwrap().links().is_empty());
|
||||
assert!(s.apply(id, Edit::RemoveLinks { pages: None }).is_err(), "nothing left to remove");
|
||||
|
||||
Reference in New Issue
Block a user