From 8745623fca1cbb2372352216e0e970ff9c4a53b1 Mon Sep 17 00:00:00 2001 From: Eric Kaden <608341+EricKaden@users.noreply.github.com> Date: Tue, 27 Oct 2026 00:39:05 -0400 Subject: [PATCH] M12: opening a document leaves the field highlight the one in front reads An open set the session's field highlight to the remembered Highlight fields for the new document's scripts, and the frame only set it back to the active document's afterwards: an edit of that document handled in between read the new one's default as app.runtimeHighlight. The open now passes the remembered setting in its own context (OpenContext::with_highlight) and the session's value stays (CodeRabbit, on #4691). --- crates/engine/src/open.rs | 8 ++++++++ crates/ui-egui/src/app/files.rs | 14 +++++++------ crates/ui-egui/tests/it/xfa.rs | 36 +++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 6 deletions(-) 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]