diff --git a/crates/engine/src/cmd/fileio/mod.rs b/crates/engine/src/cmd/fileio/mod.rs index a9e0aed35..77fde102b 100644 --- a/crates/engine/src/cmd/fileio/mod.rs +++ b/crates/engine/src/cmd/fileio/mod.rs @@ -872,7 +872,7 @@ pub fn file_stem(name: &str) -> String { /// (the title PDF, PNG and SVG metadata carry). A title of its own stays, and native files keep /// the stored title. pub fn has_own_title(doc: &vectorcraft_doc::Document) -> bool { - !doc.title.strip_prefix("Untitled-").is_some_and(|n| !n.is_empty() && n.bytes().all(|b| b.is_ascii_digit())) + !doc.title.trim().is_empty() && !doc.title.strip_prefix("Untitled-").is_some_and(|n| !n.is_empty() && n.bytes().all(|b| b.is_ascii_digit())) } pub fn titled_for_export(doc: &vectorcraft_doc::Document, path: Option<&str>, format: &str) -> Option { diff --git a/crates/engine/src/cmd/fileio/pdf.rs b/crates/engine/src/cmd/fileio/pdf.rs index 1154fe80a..df512f629 100644 --- a/crates/engine/src/cmd/fileio/pdf.rs +++ b/crates/engine/src/cmd/fileio/pdf.rs @@ -399,6 +399,8 @@ fn export_pdf(s: &mut Session, p: &Value) -> Result { let mut q = p.clone(); if let Some(o) = q.as_object_mut() { o.insert("_displayDocTitle".into(), json!(display_doc_title)); + } else { + q = json!({ "_displayDocTitle": display_doc_title }); } let (bytes, warnings) = encode(C, titled.as_ref().unwrap_or(&st.doc), &q)?; write_or_return(str_param(p, "path"), &bytes, json!({ "warnings": warnings })) diff --git a/crates/engine/src/tests_fileinfo.rs b/crates/engine/src/tests_fileinfo.rs index d9fd1854c..09d1efd17 100644 --- a/crates/engine/src/tests_fileinfo.rs +++ b/crates/engine/src/tests_fileinfo.rs @@ -316,6 +316,11 @@ fn an_untitled_document_saved_to_a_file_exports_titled_after_it() { for pdf in pdf_texts(&mut untitled) { assert!(!pdf.contains("/DisplayDocTitle true"), "{pdf}"); } + // An explicitly empty document title is also not a title to display. + std::sync::Arc::make_mut(&mut untitled.doc_mut().unwrap().doc).title.clear(); + for pdf in pdf_texts(&mut untitled) { + assert!(!pdf.contains("/DisplayDocTitle true"), "{pdf}"); + } // Saved as a file, then exported: Untitled-1 was only the name New gave it. let mut s = Session::new(); @@ -324,6 +329,9 @@ fn an_untitled_document_saved_to_a_file_exports_titled_after_it() { for pdf in pdf_texts(&mut s) { assert!(pdf.contains("/Title(Document C)") && xmp_title(&pdf).contains("Document C"), "{}", xmp_title(&pdf)); } + // Non-object parameters still preserve that the file-stem title was not user supplied. + let pdf = String::from_utf8_lossy(&b64(&s.execute("document.exportPdf", &Value::Null).unwrap())).into_owned(); + assert!(!pdf.contains("/DisplayDocTitle true"), "{pdf}"); // Opened from that file, in another session. let mut s = Session::new(); s.execute("document.open", &json!({"path": path.to_str().unwrap()})).unwrap();