From fe3e07c244d3b6bbf1772fae31a030da06adc282 Mon Sep 17 00:00:00 2001 From: mtlcl410 <2368091+mtlcl410@users.noreply.github.com> Date: Sun, 18 Oct 2026 15:07:38 +0800 Subject: [PATCH] fix(forms): an XFA form whose config forbids dynamic rendering is static (#3180) An XFA form with no AcroForm fields was always classified as dynamic, so opening it laid the template out into new pages and appended them as a revision: the pages the user saw, and any later save, were PdfCraft's layout rather than the file's own pages, with nothing saying so. Adobe Designer writes forbidden in the config packet of a static PDF form; such a form is now static and its pages are kept. /NeedsRendering still makes a form dynamic, and with no word from the config a form without fields stays dynamic as before. The config packet is found in an /XFA array or a whole-XDP stream, read with a 16 MiB decode cap, and scanned for the one element. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz --- crates/engine/src/tests.rs | 34 +++++++++++ crates/render/src/inspect.rs | 108 +++++++++++++++++++++++++++++++++-- crates/xfa/README.md | 4 +- 3 files changed, 141 insertions(+), 5 deletions(-) diff --git a/crates/engine/src/tests.rs b/crates/engine/src/tests.rs index ec305b1ca..d7f521106 100644 --- a/crates/engine/src/tests.rs +++ b/crates/engine/src/tests.rs @@ -3935,6 +3935,40 @@ fn dynamic_xfa_forms_open_with_the_values_and_rows_of_their_data() { assert!(!doc.dirty); } +/// #3180: an XFA form with no fields whose configuration says `dynamicRender` is `forbidden` is a +/// static form: its pages are the form. Opening it used to lay the template out into new pages +/// and write them as a revision, so even a save with no change replaced the pages. +#[test] +fn an_xfa_form_without_fields_that_forbids_dynamic_rendering_keeps_its_pages() { + let config = r#"forbidden"#; + let template = pdfcraft_xfa::fixtures::template(1); + let with_config = template.replacen("