diff --git a/crates/engine/src/open.rs b/crates/engine/src/open.rs index cfa50dadfa..e2736fbf4d 100644 --- a/crates/engine/src/open.rs +++ b/crates/engine/src/open.rs @@ -27,6 +27,14 @@ pub struct PreparedDocument { } impl OpenContext { + /// This context with Highlight fields `on`, which the document's scripts read as + /// `app.runtimeHighlight` while it opens. A new document opens with the remembered setting + /// while the session keeps the one of the document in front, which its scripts read. + pub fn with_highlight(mut self, on: bool) -> Self { + self.highlight = on; + self + } + /// Prepare a document without mutating the session that supplied this context. pub fn prepare_open( &self, diff --git a/crates/ui-egui/src/app/files.rs b/crates/ui-egui/src/app/files.rs index 5db8e515e2..39caf91032 100644 --- a/crates/ui-egui/src/app/files.rs +++ b/crates/ui-egui/src/app/files.rs @@ -106,9 +106,10 @@ impl PdfCraftApp { if let Some(ctx) = &self.ctx { worker.set_context(ctx); } - self.session.set_field_highlight(self.view_defaults.highlight_fields); - let receiver = - worker.submit(token, self.session.open_context(), request.name.clone(), request.path.clone(), request.password, request.input)?; + // A new document opens with the remembered Highlight fields, which its scripts read; the + // session keeps the document in front's. + let context = self.session.open_context().with_highlight(self.view_defaults.highlight_fields); + let receiver = worker.submit(token, context, request.name.clone(), request.path.clone(), request.password, request.input)?; self.next_open_token = token; self.pending_opens.push(PendingOpen { token, @@ -226,9 +227,10 @@ impl PdfCraftApp { activate: bool, ) -> Result<(), String> { use pdfcraft_render::OpenError; - // A new document opens with the remembered Highlight fields, which its scripts read. - self.session.set_field_highlight(self.view_defaults.highlight_fields); - let prepared = match self.session.prepare_open(name, path.clone(), bytes.clone(), password) { + // A new document opens with the remembered Highlight fields, which its scripts read; the + // session keeps the document in front's. + let context = self.session.open_context().with_highlight(self.view_defaults.highlight_fields); + let prepared = match context.prepare_open(name, path.clone(), bytes.clone(), password) { Ok(prepared) => prepared, Err(e @ (OpenError::NeedsPassword | OpenError::WrongPassword)) => { let error = matches!(e, OpenError::WrongPassword).then(|| "Incorrect password. Try again.".to_string()); diff --git a/crates/ui-egui/tests/it/xfa.rs b/crates/ui-egui/tests/it/xfa.rs index 8012b4a928..de01dfb82a 100644 --- a/crates/ui-egui/tests/it/xfa.rs +++ b/crates/ui-egui/tests/it/xfa.rs @@ -231,6 +231,42 @@ fn a_secured_dynamic_xfa_form_shows_its_layout_and_its_security() { h.get_by_label("Security settings"); } +/// Opening another document doesn't change the field highlight the document in front's scripts +/// read: the new one opens with the remembered Highlight fields in its own open context. Before, +/// the open set the session's value, so an edit of the first document handled before the next +/// frame read the new document's default as `app.runtimeHighlight`. +#[test] +fn opening_another_document_keeps_the_highlight_the_one_in_front_reads() { + let script = |js: &str| format!(r#""#); + let xdp = format!( + r##" + + + +"##, + look = script("xfa.form.form.seen.rawValue = String(app.runtimeHighlight);"), + ); + let mut h = open(pdfcraft_xfa::fixtures::shell(&xdp)); + let app = h.state_mut(); + // The document in front has Highlight fields on; the remembered setting is off. + app.view_defaults.highlight_fields = false; + app.views[0].highlight_fields = true; + h.run_steps(2); + let app = h.state_mut(); + let first = app.views[0].id; + app.open_bytes("next.pdf", None, pdfcraft_xfa::fixtures::shell(&pdfcraft_xfa::fixtures::template(1))).unwrap(); + // Before the next frame, the first document's script reads its own setting. + app.session.apply(first, pdfcraft_engine::Edit::XfaEvent { som: "form[0].look[0]".into(), activity: "click".into() }).unwrap(); + let seen = app.session.get(first).unwrap().form.iter().find(|f| f.name == "seen").map(|f| f.value.clone()).unwrap_or_default(); + assert_eq!(seen, vec!["true".to_string()], "the first document's script reads its own Highlight fields"); +} + /// A form that turns field highlighting on (`app.runtimeHighlight = true` in a `layout:ready` /// script) gets it, and so does the next document, as with the Highlight fields button. #[test]