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).
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).
* 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>
A text field PdfCraft added showed its typed text in Acrobat only while
the field had focus: as soon as the user clicked elsewhere the text
vanished (it was still stored, and printed). PDF-XChange Editor and
PDFgear were fine, and the same field made by MuPDF was fine in Acrobat.
Bisected in Acrobat with one-change variants of the same file: only the
variants whose /DR fonts are objects (or that have no /DR) keep the text.
The appearance stream's own fonts, /P, the appearance layout and /DA 0
made no difference. PdfCraft wrote Helv, TiRo and Cour inline in /DR.
ensure_form now adds them as objects, and turns fonts an earlier save
wrote inline into objects too (same dictionaries). An indirect /DR or
/Font stays the object it is. The XFA-to-AcroForm writer does the same.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The text layout cut each embedded value to the bytes its block had left, but
the resolver cloned the whole value first. With a byte or two left and a
value starting with a multibyte character, every later run cloned the full
value and kept none of it. The resolver is given the bytes left and returns
only a prefix that fits.
A positioned root draws its children instead of flowing them, so nested
repeating subforms under it multiplied their instances without spending
the measurement budget that flowed instances spend. Drawing a subform
instance spends it too.
Writing a value at a high index creates every missing sibling before it,
each with its own copy of the name. The node budget counted siblings but not
their names, so a long name with a high index made thousands of copies of
it. The write's budget also counts the bytes of the names it creates; a
path past it is skipped with the existing warning.
Converting an imported data file copied each element's and attribute's
resolved namespace URI, so a long namespace declared once on the root was
copied into every element that inherits it; only the node count was
limited. The import counts the names, namespaces, attributes and text it
copies against a byte budget of four times the file-size limit, and refuses
the file as too large past it.
write_data_ops expanded every instance-count op into one queued node per
instance, then deduplicated the pass. A script adding rows one at a time
asks for one more instance each time, so n rows queued about n*n/2 nodes
before the deduplication. Each op queues only the instances the pass has
not queued yet, and a budget bounds the instances queued across passes
that removals separate, with a warning past it.
Every instance of a repeated subform records its own copy of each script,
and only the number of events was capped. A long script inside nested
repeating subforms was copied once per instance before any script ran. The
events hold at most as much script text as the XFA packets may; past that
the live form is marked truncated, as it is past the event cap.
Rich text resolved every embedded-field reference to a fresh copy of the
field's value, so a template repeating one reference to a long value many
times laid out a copy per reference. One text block expands at most as many
bytes of embedded values as a text of its own may hold; past that the
values are cut.
Text layout broke a word wider than its line by measuring the whole growing
piece after every character, and counting its characters again each time.
A long unbroken word in a wide box with a small font made that quadratic.
The piece's advance is kept as a running sum of character widths instead.
The packet reader decoded the stream of every /XFA array entry and
charged only the decoded output to its 64 MB budget, so one stream that
decodes to almost nothing (Flate over hex whitespace), listed many
times, repeated a large decode for free. A stream reference already
read is skipped.
Nested repeating subforms multiplied their instances (up to 50 per level
over 64 levels), and an empty instance neither measured nor placed
anything, so it spent none of the measurement or item budgets. Each
instance now counts as a measurement, and layout stops with TooLarge
once the budget is spent.