From 257c843eed0fffe5599df411649eab523dd799bd Mon Sep 17 00:00:00 2001 From: Eric Kaden <608341+EricKaden@users.noreply.github.com> Date: Mon, 19 Oct 2026 23:39:31 -0400 Subject: [PATCH] Forms: doc comments for the functions this change touches --- crates/automation/src/a11y.rs | 1 + crates/engine/src/lib.rs | 4 ++++ crates/engine/src/tests.rs | 3 +++ crates/js/src/lib.rs | 2 ++ crates/js/src/tests.rs | 9 +++++++++ crates/js/src/xfa.rs | 2 ++ crates/ui-egui/src/lib.rs | 7 +++++++ crates/xfa/src/tests.rs | 2 ++ 8 files changed, 30 insertions(+) diff --git a/crates/automation/src/a11y.rs b/crates/automation/src/a11y.rs index a7c05e14e9..39253bbf54 100644 --- a/crates/automation/src/a11y.rs +++ b/crates/automation/src/a11y.rs @@ -646,6 +646,7 @@ impl Automation { } } +/// A script's request as `js_run` reports it: one small object per kind of request. fn request_json(r: &pdfcraft_engine::js::Request) -> Value { use pdfcraft_engine::js::Request as R; match r { diff --git a/crates/engine/src/lib.rs b/crates/engine/src/lib.rs index dbd35e55df..e9de677192 100644 --- a/crates/engine/src/lib.rs +++ b/crates/engine/src/lib.rs @@ -2265,6 +2265,8 @@ struct EditCtx { } impl EditCtx { + /// The context for one edit: `now` (the session's clock) dates it, and with `salt` seeds the + /// ids it makes. fn new(now: Option, salt: u64) -> Self { let mut seed = 0x9E37_79B9_7F4A_7C15u64 ^ salt; if let Some(t) = now { @@ -3375,6 +3377,8 @@ impl Session { Ok(self.commit_open(prepared)) } + /// What [`OpenContext::prepare_open`] runs inside its panic guard: read, decrypt and lay out + /// the document, and run an XFA form's opening scripts. fn prepare_open_unguarded( context: &OpenContext, name: String, diff --git a/crates/engine/src/tests.rs b/crates/engine/src/tests.rs index 3a34b00d56..8ea120b4b6 100644 --- a/crates/engine/src/tests.rs +++ b/crates/engine/src/tests.rs @@ -6107,6 +6107,9 @@ fn undo_never_makes_an_unsaved_document_clean() { assert!(!s.get(new).unwrap().dirty, "once saved, undo back to the saved state is clean"); } +/// layout:ready scripts run once on opening: the root's turns field highlighting on (only when it +/// is off), a field's sets a value and a later script reads the new highlight, while page +/// numbering is left to the layout and form:ready is another event. #[test] fn a_forms_layout_ready_scripts_run_once_it_is_laid_out() { let bytes = Arc::new(pdfcraft_xfa::fixtures::shell(&pdfcraft_xfa::fixtures::layout_ready_template())); diff --git a/crates/js/src/lib.rs b/crates/js/src/lib.rs index 9ace0cbc4f..3105321b15 100644 --- a/crates/js/src/lib.rs +++ b/crates/js/src/lib.rs @@ -911,6 +911,8 @@ fn color_object(ctx: &mut Context) -> JsObject { o.build() } +/// The AcroForm object model as globals: the document's methods and properties (`getField`, +/// `numPages`, `info`, …), `app`, `util`, `console`, `display` and `color`. fn install(ctx: &mut Context) -> JsResult<()> { let globals: [(&str, usize, NativeFunction); 9] = [ ("getField", 1, NativeFunction::from_fn_ptr(get_field)), diff --git a/crates/js/src/tests.rs b/crates/js/src/tests.rs index 43628137c6..1bd0be0828 100644 --- a/crates/js/src/tests.rs +++ b/crates/js/src/tests.rs @@ -15,6 +15,7 @@ fn fields() -> Vec { ] } +/// The document these tests' scripts run in. fn doc() -> DocInfo { DocInfo { file_name: "order.pdf".into(), num_pages: 3, page: 0, info: vec![("title".into(), "Order".into())], highlight: false } } @@ -380,6 +381,7 @@ mod xfa_model { } } + /// Run JavaScript `script` as `target`'s `activity` script on [`form`]. fn go(script: &str, target: &str, activity: &str) -> XfaOutcome { let ev = XfaEvent { activity: activity.into(), target: target.into(), ..Default::default() }; let doc = XfaDoc { file_name: "f.pdf".into(), page: 1, page_count: 3, ..Default::default() }; @@ -594,6 +596,7 @@ mod formcalc { use crate::formcalc::run_formcalc; use crate::xfa::*; + /// Run FormCalc `script` as `target`'s `activity` script on [`form`]. fn go(script: &str, target: &str, activity: &str) -> XfaOutcome { let ev = XfaEvent { activity: activity.into(), target: target.into(), ..Default::default() }; let doc = XfaDoc { file_name: "f.pdf".into(), page: 1, page_count: 3, ..Default::default() }; @@ -1110,6 +1113,8 @@ mod session { assert_eq!(s.dead(), None); } + /// A JavaScript script past its time is abandoned within the deadline, and the session runs + /// nothing after it; a FormCalc one stops itself or is abandoned too. #[test] fn a_script_past_its_time_is_abandoned_and_the_session_is_dead_after_it() { let mut s = XfaSession::new(XfaDoc::default()); @@ -1137,6 +1142,8 @@ mod runtime_highlight { use super::*; use crate::xfa::{XfaDoc, XfaEffect, XfaEvent, XfaNode, run_xfa}; + /// `app.runtimeHighlight` in AcroForm scripts reads the viewer's setting, and setting it asks + /// for the change once and reads back the new value. #[test] fn app_runtime_highlight_reads_the_viewers_setting_and_asks_to_change_it() { let ev = Event::field("Calculate", "total", ""); @@ -1149,6 +1156,8 @@ mod runtime_highlight { assert_eq!(o.requests, vec![Request::Highlight(true)]); } + /// The same in XFA scripts, where the change is an effect; nothing is asked for when the + /// setting is already what the script wants. #[test] fn xfa_app_runtime_highlight_reads_the_setting_and_records_a_change() { let ev = XfaEvent { activity: "layoutReady".into(), target: "form1[0]".into(), ..Default::default() }; diff --git a/crates/js/src/xfa.rs b/crates/js/src/xfa.rs index 53fd7582f0..f91a33c969 100644 --- a/crates/js/src/xfa.rs +++ b/crates/js/src/xfa.rs @@ -1118,6 +1118,8 @@ fn xfa_resolve(ctx: &mut Context, many: bool) -> JsResult { resolver(ctx, current, many) } +/// The XFA object model as globals for one script: `xfa` (form, host, layout, event), `event` +/// (the same object as `xfa.event`), `this` as node `current`, `app`, `console` and `util`. fn install(ctx: &mut Context, event: &XfaEvent, doc: &XfaDoc, current: usize) -> JsResult<()> { let rw = Attribute::CONFIGURABLE; let form = node_object(ctx, 0)?; diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index d3c8dfabd0..630841ff5b 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -1150,6 +1150,8 @@ impl PdfCraftApp { self.try_open(name, path, std::sync::Arc::new(bytes), None, activate) } + /// Hand `request` to the background open worker (started on first use); the result arrives + /// later as a pending open, under the returned token. #[cfg(not(target_arch = "wasm32"))] fn schedule_open(&mut self, request: OpenRequest) -> Result { if self.open_worker.is_none() { @@ -1275,6 +1277,8 @@ impl PdfCraftApp { } } + /// Open `bytes` on this thread: ask for a password if the document needs one, else add it + /// as a tab (in front when `activate`). fn try_open( &mut self, name: &str, @@ -1312,6 +1316,8 @@ impl PdfCraftApp { self.finish_open(name, path, bytes.len(), prepared, activate).map(|_| ()) } + /// Add a prepared document as a tab: its view, the recent-files entry, and what its scripts + /// said while it opened (at once in front, or when a background tab is first selected). fn finish_open( &mut self, name: &str, @@ -3123,6 +3129,7 @@ impl eframe::App for PdfCraftApp { self.process_picked(); } + /// One frame of the whole window. fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) { let ctx = ui.ctx().clone(); i18n::set_current(i18n::Lang::from_pref(&self.language)); diff --git a/crates/xfa/src/tests.rs b/crates/xfa/src/tests.rs index d8695a17c1..c51438db16 100644 --- a/crates/xfa/src/tests.rs +++ b/crates/xfa/src/tests.rs @@ -2068,6 +2068,8 @@ fn som_indices_count_earlier_same_named_siblings() { assert_eq!((0..=children.len()).map(|i| sibs.at(i)).collect::>(), [0, 0, 1, 0, 2, 1, 0]); } +/// `ready` is two events: `ref="$layout"` is layout:ready (`layoutReady`), anything else stays +/// form:ready (`ready`), in the template and in the live form; page numbering is recognized. #[test] fn a_layout_ready_event_is_told_apart_from_form_ready() { let (tpl, _) = parse(&crate::fixtures::layout_ready_template()).unwrap();