144 Commits
Author SHA1 Message Date
Grzegorz MartensandClaude Opus 5.5 41bf288a23 M12: a turned draw past the edge of the page stays where it turned to
Nothing tested one that stands off the page: it isn't moved back or cut, as an upright one isn't.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
2026-11-01 13:46:01 +01:00
Grzegorz MartensandClaude Opus 5.5 025050942c M12: each of the nine anchors turns, at each turn
Rotation was tested from the top left and the bottom right. The other seven share that code, but
nothing held them to it. What is asked for comes from the box's corners in the test, not from layout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
2026-11-01 08:46:27 +01:00
Grzegorz MartensandClaude Opus 5.5 2afbf55cd2 M12: an XFA draw placed by position turns about its anchor
Nothing read rotate, so a turned line, picture or label was drawn as if it
stood upright: part of #5561. XFA gives the angle in degrees counter-clockwise
about the anchor, and Acrobat's flattened page for that issue's form puts the
three turned lines exactly there, which the test holds it to.

A turned draw is one item: a page break moves it whole, and what it holds is
written unturned under one matrix, so text, pictures and borders need nothing
of their own. The page count and link annotations look inside it, and its
container grows to the box it stands in. Fields, subforms and draws in a flow
don't turn yet.

That issue's own form is static, so it already shows Acrobat's page: this is
for dynamic forms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
2026-11-01 02:59:32 +01:00
Dylan M. Taylor f76dbb9e8c deps: bump tar, zip, roxmltree, rustls-webpki and symphonia to their latest versions (#5381)
- `zip`: 9.1.0 → 9.1.3

Requirement `roxmltree` 0.20 → 0.21: `ParsingOptions` gained `entity_resolver` (initializers take `..Default::default()`, i.e. none, as before) and is no longer `Copy` (two functions build it with a closure, the pattern merge.rs already used).
2026-10-29 22:21:27 -04:00
FredApps d1fcc12e07 Integrate KenM76 PR #4943 2026-10-29 02:36:20 +01:00
Dylan M. Taylor 9530dbb3e8 Refactor xfa for strict Clippy checks 2026-10-27 23:12:52 +00:00
KenM76andClaude Opus 5.5 fd8c8c185d fix(xfa): repair a BMP offset that points at the header's end with masks or a palette to follow
Review follow-up: an offset equal to the end of the info header is only
right when no bitfield masks or colour table come after it; otherwise the
pixels were read from the masks or the table. It is now repaired like an
offset inside the headers. Offsets strictly inside the masks or table are
still taken as given (they may come from an overstated biClrUsed).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SqmHYx8FiWM5PcsoiErgp9
2026-10-27 05:43:31 -04:00
KenM76andClaude Opus 5.5 de9ab5370e fix(xfa): leave a 16-byte BMP header to the decoder; test core headers and a huge colour count
Review follow-up: the repair reads the 40-byte header's compression and
colour count, which a 16-byte OS/2 header does not have. New cases pin
a 12-byte core header (3-byte palette entries) and a biClrUsed of u32::MAX.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SqmHYx8FiWM5PcsoiErgp9
2026-10-27 05:03:47 -04:00
KenM76andClaude Opus 5.5 38c9482191 fix(xfa, create): read a BMP's pixels from after its headers when its offset points into them
LiveCycle Designer wrote BMPs whose file header gives bfOffBits = 0. image
(0.25) seeks to that offset as given, so the pixels were read from the file
header on and the picture was drawn shifted and wrapped around (#4937).

`pdfcraft_xfa::image::bmp_with_pixel_offset` recomputes the offset from the
info header (its size, BI_BITFIELDS masks in a 40-byte header, the palette)
when the declared one lies inside the headers and the computed one fits in
the file; anything else is passed through unchanged and not copied. XFA
pictures (size and decode) and `create::from_images` both go through it, so
pdfcraft-create gains a dependency on pdfcraft-xfa (L4 -> L3).

Fixes #4937

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SqmHYx8FiWM5PcsoiErgp9
2026-10-27 05:00:44 -04:00
aiongg f022ef0671 style: cargo fmt on moved files 2026-10-27 00:34:32 +00:00
aiongg 0988209798 refactor(xfa): split pdf.rs into pdf/
New modules: helpers, strip.
2026-10-26 22:18:50 +00:00
aiongg 3da49321f2 refactor(xfa): split layout.rs into layout/
New modules: items, helpers, pages, flow, measure, draw, field.
2026-10-26 22:18:50 +00:00
aiongg 4e278cb5fc refactor(xfa): split data.rs into data/
New modules: path, dates, values, build, merge, write, import, passwords.
2026-10-26 22:18:50 +00:00
skylar fc578a0b02 chore(deps): bump 11 safe dependency updates 2026-10-25 16:36:22 -06:00
mtlcl410andClaude Opus 5.5 6918d0be21 M6: a static XFA form whose data fills thousands of fields opens in seconds (#4638)
Opening a static XFA form gives its fields the values in its datasets
(a form filled in by another application). Each value went through
forms::set_value, which reads the whole field tree to find the field,
writes it, and recalculates, reading the tree again. With n values that
is about 2n readings of n fields: quadratic. A public 136-page form with
about 6,000 fields took 261 s to open, a 95-page one with about 4,000
took 112 s; 8,000 synthetic fields took over ten minutes.

forms::set_values fills a batch as set_value fills each in turn, reading
the form once and recalculating once after the last value (the
calculation order, ISO 32000-2 Table 224 /CO, runs once over the final
values). Fields with the same fully qualified name (12.7.4.2) still share
the value. A name the batch already wrote, or a twin of it, makes the
form be read again first, so each write starts from what the earlier one
left, as one by one. Each value reports its own result; a failed
recalculation fails the batch, as it fails set_value. The engine collects
the changed values and fills them with set_values, finding fields by name
through a map rather than a scan.

The two forms now open in 4 s and 3 s, with the same fields, values,
warnings and document information as before; 8,000 synthetic fields open
in 1.5 s.

Tests: set_values matches set_value one by one (values, twins, the
calculated total, every appearance, saved; refusals for an unknown name,
a read-only field, an unknown option and clearing a no-toggle-off radio
group the batch selected); it reads the form a fixed number of times; the
engine takes 59 data values on a 60-field static form exactly as filling
them one by one does (the read-only one refused); and opening 800 fields
takes under 16 times as long as 100 (about 4x now, about 48x before).


Claude-Session: https://claude.ai/code/session_01CBVyQEwtmEw3mS1MoAiwrK

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 10:02:35 -04:00
Eric Kaden 3f5d8d06fe M9: name a laid-out XFA form's signature fields by their SOM path, so other viewers find the signature (#4507)
* M9: name a laid-out XFA form's signature fields by their SOM path, so other viewers find the signature

* M9: doc comments on the functions the signature naming touches

* M9: say other viewers in the signature naming's comments

* M9: a new layout keeps a signature a generated signature box holds

* M9: the re-layout test checks the signature's picture is kept too

* M9: a signature field named by its SOM path doesn't repeat a name a field already has

* M9: every name a field of the pass takes is known before a signature field is named, in either order

* M9: the signed-box test's doc comment is back on its test

A merge had left it above the next test, which has its own.
2026-10-25 10:01:53 -04:00
NetterSilverandClaude Haiku 5.5 29e08fadce Reject non-hex characters in XFA image hash parsing (#4630)
Found while testing crates/xfa/src/pdf.rs:50-52 (parse_hex32)

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-25 09:59:51 -04:00
jonathanwxh-cell 24edde6563 forms: clear typed XFA password field values from datasets on save (#3944) (#4506) 2026-10-24 21:08:21 -04:00
Dylan M. Taylor f4f91d0d5c fix(xfa): require full save when stripping XFA packets (#4568) 2026-10-24 21:03:25 -04:00
9aef0dfb78 refactor(xfa): explicit model imports (Sonar S2208) (#4403)
* refactor(xfa): replace model wildcard imports with explicit names (Sonar S2208)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(xfa): complete explicit model imports

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(xfa): drop unused model imports

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Import Corner, which main's parse.rs now uses

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-24 10:31:05 -04:00
Eric Kaden 96cf936b31 M12: XFA check boxes sit where their margins, caption and alignment put them (#4300)
* M12: XFA check boxes sit where their margins, caption and alignment put them

* M12: a check box's automatic caption room and auto height follow the box as drawn

* M12: a caption reserve of zero sizes the caption to its content, as no reserve does
2026-10-24 10:30:11 -04:00
aiongg 2208dc16c8 Integration: cargo fmt 2026-10-24 07:32:52 +00:00
aiongg 9705e7a6c1 Merge track r3-t03 2026-10-24 06:39:33 +00:00
aiongg c53757939f Merge PR #4338: M12: flowed XFA subforms are drawn with their border and fill
crates/xfa/src/tests.rs: both sides' appended tests kept.
parity/acrobat-features.toml: form.xfa-dynamic evidence and notes: both sides' insertions.
2026-10-24 06:24:41 +00:00
aiongg a637c39435 Merge PR #4319: M12: XFA borders and rectangles with rounded corners are drawn rounded
parity/acrobat-features.toml: form.xfa-dynamic evidence: both sides' entries; notes: both sides' insertions.
2026-10-24 06:24:30 +00:00
aiongg 541c82d59f Merge PR #4318: M12: links in XFA rich text become clickable links
crates/xfa/src/tests.rs: both sides' appended tests kept.
parity/acrobat-features.toml: form.xfa-dynamic evidence and notes: both sides' insertions (word-level merge).
2026-10-24 06:24:04 +00:00
aiongg 761353775b Merge PR #4317: M12: round XFA check buttons draw a round background and border 2026-10-24 06:23:48 +00:00
aiongg bcbd9cbf4e Merge PR #4287: M12: XFA text is measured at its standard-14 font's own widths
parity/acrobat-features.toml: form.xfa-dynamic evidence: both sides' entries; notes: PR's metrics sentence replaces 'metrics are approximate' on top of main's text (word-level merge).
2026-10-24 06:22:55 +00:00
aiongg 2a1ceebb4f Merge PR #4339: M6: fields that don't scroll stop taking text when full
parity/acrobat-features.toml: form.fill-text-field evidence is the union of both sides; notes keep both sides' sentences (DoNotScroll clause and the Password sentence).
2026-10-24 06:22:02 +00:00
aiongg c0687edbbe Merge PR #3552: M12: a date typed by another of an XFA field's edit patterns is kept in its first 2026-10-24 06:22:01 +00:00
aiongg 1fd37592d4 Merge PR #3401: M12: laying out a dynamic XFA form takes off the usage rights it voids
parity/acrobat-features.toml: form.xfa-dynamic evidence list: both sides' entries; notes: both sides' insertions (word-level merge).
2026-10-24 06:22:01 +00:00
aiongg 0cfde22386 Merge PR #3488: fix(forms): write each /DR font as its own object, so Acrobat keeps typed text (#3441)
crates/forms/src/tests.rs: append conflict, kept both tests.
2026-10-24 06:21:22 +00:00
aiongg 4fedfe7e8c Merge PR #2648: fix(xfa): skip PDF fallback scripts while XFA layout is active
crates/engine/src/js.rs: kept main's DocInfo.xfa field and multi-line layout, added the PR's xfa_active gate on doc_scripts.
2026-10-24 06:21:20 +00:00
a047c6ba09 chore: resolve SonarCloud maintainability issues (#4356)
* chore: resolve SonarCloud maintainability issues

* fix(packaging): use verify_sha256 helper function

* style: cargo fmt

* fix: restore wildcard imports and fix method-reference type errors

Revert the glob-import expansions (they missed SomIndices and left unused
imports), revert char::is_ascii_digit where the iterator yields char by
value, and pass the content slice to prune_doomed_xobjects as &[Vec<u8>].

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Keep XObject decodability check without binding content in interp

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Dylan Taylor <dylan@craftmaker.dev>
2026-10-23 23:28:18 -04:00
Eric Kaden 2fc251193e M12: a test that a section whose first child moves to the next page takes its border along 2026-10-23 23:16:10 -04:00
Eric Kaden 4d190aaff8 M12: the parity note and test say which sections lose their border 2026-10-23 22:52:53 -04:00
Eric Kaden cafd507f29 M12: page breaks of a section's own keep the border around it, a leader is given room with its row, and what runs off a page costs its section the border 2026-10-23 22:51:54 -04:00
Eric Kaden 35716c6282 M12: a flowed table a page break cuts between its rows keeps its border on each page 2026-10-23 22:29:04 -04:00
Eric Kaden 3cf6b0e589 M12: docstrings for the layout helpers and test the flowed-border change touches 2026-10-23 22:21:38 -04:00
Eric Kaden cc6b042f0d M12: a flowed subform's repeated top margins give way to a child that fits a fresh content area only without them 2026-10-23 22:15:07 -04:00
Eric Kaden a7d86dea76 M12: a flowed subform's last part keeps its bottom margin inside the content area 2026-10-23 22:05:46 -04:00
Eric Kaden d7da5dfe29 M12: a flowed XFA subform a page break cuts gets a closed border on each page, its margins repeated 2026-10-23 21:54:55 -04:00
Eric Kaden f5e74991ed M12: flowed XFA subforms are drawn with their border and fill 2026-10-23 19:30:43 -04:00
Eric Kaden 64bdea4e61 M6: fields that don't scroll stop taking text when full 2026-10-23 19:25:32 -04:00
Eric Kaden 352ebb1477 M12: a backslash ends a web link's host, as web addresses read it 2026-10-23 17:28:22 -04:00
Eric Kaden 3355edad42 M12: only a link's own underline joins its pieces, and web links need a host 2026-10-23 17:19:25 -04:00
Eric Kaden 3cf6e5f716 M12: a link's pieces don't join across a rule, picture or field between them 2026-10-23 17:05:18 -04:00
Eric Kaden d91028a990 M12: a link's address is shared by its runs, words and spans, not copied 2026-10-23 16:47:19 -04:00
Eric Kaden 0008a18345 M12: XFA borders and rectangles with rounded corners are drawn rounded 2026-10-23 16:41:22 -04:00
Eric Kaden 1c4a481ea3 M12: round XFA check buttons draw a round background and border 2026-10-23 16:19:43 -04:00