69 Commits
Author SHA1 Message Date
aiongg 06959df890 Integration: execMenuItem requests go through the request cap (#3580)
A script looping on app.execMenuItem could queue unlimited requests; they now follow the same count and byte limits as other requests.
2026-10-24 08:15:46 +00:00
aiongg f017ca3b78 Merge PR #3580: M6: form buttons show the side panels (app.execMenuItem)
crates/js/src/lib.rs: module doc app/util list has execMenuItem and scand; install() doc comment from main.
crates/js/src/tests.rs, crates/engine/src/tests.rs: both sides' appended tests kept.
parity/acrobat-features.toml: js notes: execMenuItem wording plus scand wording.
2026-10-24 06:23:47 +00:00
aiongg 5990381c9c Merge PR #3549: M6: util.scand reads dates as another viewer does 2026-10-24 06:22:59 +00:00
aiongg 3f622963f0 Merge PR #4299: Omit minus sign when FormCalc Format() rounds to zero 2026-10-24 06:22:56 +00:00
aiongg c24e90b59c Merge PR #3985: M6: a document script that throws no longer stops the form's other scripts (#3940)
crates/automation/src/tools.rs: js_run description: both sides' wording merged.
2026-10-24 06:22:15 +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
NetterSilverandClaude Haiku 5.5 afcc54fddc Omit minus sign when FormCalc Format() rounds to zero
Found while testing crates/js/src/formcalc.rs:2328-2330 ("format" number-picture branch, `if num < 0.0 { text = format!("-{text}") }`)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-23 20:53:02 +02:00
Eric Kaden 44b7e0a40f Merge remote-tracking branch 'upstream/main' into fix/exec-menu-attachments
# Conflicts:
#	crates/js/src/lib.rs
#	crates/js/src/tests.rs
#	parity/acrobat-features.toml
2026-10-23 10:43:34 -04:00
Eric Kaden c141c94c06 Merge remote-tracking branch 'upstream/main' into fix/util-scand
# Conflicts:
#	crates/js/src/lib.rs
#	crates/js/src/tests.rs
#	parity/acrobat-features.toml
2026-10-23 10:27:32 -04:00
mtlcl410andClaude Opus 5.5 994ce63099 M6: a document script's error is told apart by where it came from, not its wording (#3940)
Review follow-up on #3985: JsOutput deduplicated document-script errors by
their text (document script N: ...), so a field script that threw the
same words was dropped by append, and a document script's error was
dropped by absorb when a field script had already reported that text.
JsOutput now records which errors came from document scripts
(doc_errors) and deduplicates only those; pdfcraft_js::is_doc_error,
which guessed from the wording, is removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0175FWj4xFhMhSH3UpMU8DSC
2026-10-23 22:25:57 +08:00
mtlcl410andClaude Opus 5.5 a7afaacbb9 M6: merged script output reports a document script's error once too (#3940)
Review on #3985 (benandez): JsOutput::absorb reported a failing document script once, but append
added every error again, so merging two outputs repeated it. pdfcraft_js now says whether an
error is a document script's (is_doc_error, next to the doc_error format), and append skips one
already reported; each field script error is still its own.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 22:25:57 +08:00
mtlcl410andClaude Opus 5.5 a8beb90ccf M6: a document script refused before running is skipped and reported too (#3940)
CodeRabbit on #3985: a document script over the size or nesting limit made `run`
return before any script ran, so the field script failed as before. It is now
skipped (never evaluated, as the limits require), reported in its place in
doc_errors, and the other scripts and the field script still run. The field
script's own limits still refuse it outright.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 22:25:57 +08:00
mtlcl410andClaude Opus 5.5 77db1bd27f M6: parity note for document scripts that throw (#3940)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 22:25:57 +08:00
mtlcl410andClaude Opus 5.5 e76ebb9ea3 M6: a document script that throws no longer stops the form's other scripts (#3940)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 22:25:57 +08:00
Eric Kaden 8f292c66ae M6: scripts see xfa_version, and xfa_installed in XFA forms (#4142) 2026-10-23 10:19:09 -04:00
NetterSilverandClaude Haiku 5.5 3ee6a83e09 Accept long unit names in FormCalc UnitValue (#4116)
Found while testing crates/js/src/formcalc.rs:2526-2532 (UnitValue per_in table; UnitType at :2510-2516)

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-23 10:18:55 -04:00
NetterSilverandClaude Haiku 5.5 c32c2ce09f Fix FormCalc Str() printing small negative numbers as "-0" (#4108)
Found while testing crates/js/src/formcalc.rs:716-720 (fixed), used by Str at :2216

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-23 10:18:45 -04:00
Eric Kaden 8f82bfccec Merge remote-tracking branch 'upstream/main' into fix/exec-menu-attachments
# Conflicts:
#	crates/engine/src/tests.rs
2026-10-22 23:09:22 -04:00
aiongg d67c4b3059 fix(js): an XFA value past the effect cap leaves the field unchanged 2026-10-22 21:41:50 +00:00
aiongg e541151389 fix(js): XFA presence and access change the snapshot only when their effect is kept 2026-10-22 21:41:01 +00:00
aiongg fd2e13f332 M8: XFA instance changes reserve their effect before changing the snapshot 2026-10-22 21:35:52 +00:00
aiongg 2ece498ffc fix(js): charge both copies of a written XFA value before keeping either
set_value charged the snapshot's copy, changed the field, then charged the
effect's copy in push. When only the first fit, the effect was dropped while
later reads in the script saw the new value. Both copies are charged at once
before the field changes.
2026-10-22 20:21:21 +00:00
Eric Kaden 6c0fd0f353 Merge remote-tracking branch 'upstream/main' into fix/util-scand
# Conflicts:
#	crates/js/src/lib.rs
2026-10-22 13:23:32 -04:00
aiongg 72fd2a1b24 fix(js): bound the text an XFA script's effects and values hold
The XFA script host capped the number of effects but not their size: URLs,
focus targets and resetData lists were kept whole, a resetData list kept
every repeated name, and values written to fields were each cut but not
counted together. A loop repeating one long script-built string kept a copy
per effect or field. URLs, focus targets and reset names are cut to a
message's length, reset lists name each field once, and every effect,
console line and value written charges a byte budget for the run; past it
they are left out and noted. FormCalc charges an assignment to many fields
once per field copied.
2026-10-22 17:22:50 +00:00
aiongg a5cfc3eec4 fix(js): cap a form script's alerts, console lines and requests
The AcroForm script host kept every alert, console line and request a
script made, each as long as the script made it. A loop printing a long
script-built string held a copy per iteration. The host applies the XFA
host's limits: message and console counts, the effect count for requests,
each message, URL and field name cut to a line, and a byte budget across
all of them, with a closing console line saying how many were left out.
2026-10-22 17:22:50 +00:00
aiongg 2e9b247f3f fix(js): read printd literals in linear time
util.printd measured the run of identical characters at every position of
the format, literals included, but copied a literal one character at a time.
A format with a long stretch of one literal character rescanned the rest of
that stretch at every step: quadratic work from one script-built string.
Only the date letters are read as runs now.
2026-10-22 17:22:50 +00:00
aiongg a525cf1d42 fix(js): refuse code compiled from strings that skipped the script checks
eval and the Function constructors compiled code built at run time, which never
passed the size and nesting checks a script passes before it runs, so a short
form script could hand boa's recursive parser a deeply nested string and
overflow the stack. Form scripts now refuse to compile code from strings. XFA
scripts, which the runner itself starts through eval, hold such code to the
same checks as the script.
2026-10-22 13:18:26 -04:00
Eric Kaden ae69aea627 M6: doc comments on every Panel variant 2026-10-22 09:22:27 -04:00
Eric Kaden 4665685446 Merge remote-tracking branch 'upstream/main' into fix/exec-menu-attachments
# Conflicts:
#	crates/engine/src/tests.rs
#	crates/js/src/tests.rs
#	crates/ui-egui/tests/forms.rs
2026-10-22 03:19:20 -04:00
Eric Kaden 82115ed65c Merge remote-tracking branch 'upstream/main' into fix/util-scand
# Conflicts:
#	crates/js/src/tests.rs
2026-10-22 03:15:57 -04:00
aiongg dcf2802f96 Merge r2 track t15: mixed: accessibility-tags, dialogs-prefs, javascript, organize-pages
# Conflicts:
#	crates/edit/src/tests.rs
#	crates/engine/src/tests.rs
2026-10-22 02:23:22 +00:00
aiongg a0a9e3370e Merge PR #3408: M12: an XFA script that fails partway keeps what it changed before the error
crates/engine/src/tests.rs: union of #2624's tests and #3408's test.
parity/acrobat-features.toml: form.xfa evidence lists unioned, notes take both sides' insertions.
2026-10-22 01:47:22 +00:00
aiongg ae9cd9f623 Merge PR #3004: Zero-pad required integer digits in FormCalc Format() 2026-10-22 01:45:13 +00:00
aiongg c83be3002a Merge PR #3718: Return empty WordNum result when cents rounding carries to 1e12 2026-10-22 01:45:12 +00:00
aiongg 6e2a449bf7 Merge PR #3318: M6: Optimize AcroForm JavaScript snapshots and diffs
parity/acrobat-features.toml: form calculation order entry keeps main's commands, tools and notes; evidence is the union of both sides.
2026-10-22 01:44:59 +00:00
aiongg 9cb8f52294 Merge PR #3782: M6: XFA formattedValue shows a date in the field's display picture 2026-10-22 01:44:53 +00:00
aiongg be1b2bb882 Merge PR #2963: Keep seconds in FormCalc Time2Num/IsoTime2Num for ISO 8601 times 2026-10-22 01:44:49 +00:00
Eric Kaden 4ee87801b2 M6: util.scand's linear-time test allows a loaded runner (10 s) 2026-10-21 19:48:31 -04:00
Eric Kaden 628c827572 Merge remote-tracking branch 'upstream/main' into fix/util-scand
# Conflicts:
#	crates/js/src/formcalc.rs
2026-10-21 19:42:26 -04:00
Dylan M. Taylor 606c560d24 Use chrono instead of hand-rolled UTC conversion (#3824)
* Use chrono for UTC/calendar conversion instead of hand-rolled copies

Replaces the hand-rolled civil_from_days/days_from_civil copies and the
leap-year/month math around them (log timestamp, PDF /Info dates, ASN.1
UTCTime/GeneralizedTime, FormCalc Date/Num2Date, the Combine modified-time
stamp, the form date picker, and the demo-PDF timestamps) with chrono as a
workspace dependency. The engine's existing chrono (clock) is lifted to the
workspace. Every output format is unchanged and pinned by tests. CLAUDE.md now
says time goes through chrono.

Follow-up to storytold/cadcraft#1785

* Guard chrono date paths: no panic on overflow, no '+' on 5-digit years

Systemic chrono follow-ups to the UTC/calendar PR:

- logging::timestamp and combine_ui::utc_stamp dropped chrono's
  From<SystemTime> (which unwraps internally and panics on a clock past
  year 262143) for the fallible DateTime::from_timestamp, reading an
  out-of-range clock as the epoch, as the old clamping code did.
- timestamp, utc_stamp, pdf_date and the xtask Stamp now write the year
  with {:04} instead of %Y, which prefixes a '+' before years past 9999;
  the old hand-rolled code wrote the plain zero-padded year.
- forms_ui calendar navigation and length, and formcalc days_in, use
  checked_add for the December year successor so y + 1 can't overflow at
  i32::MAX / i64::MAX (reachable from a parsed or persisted date).

Docstrings added to the chrono-touched civil_from_days and Time::from_unix
for the docstring-coverage gate. Tests cover the out-of-range-epoch and
10000-01-01 cases for each.

* Don't build an unrepresentable SystemTime in the far-future test

UNIX_EPOCH + Duration::from_secs(u64::MAX / 2) overflows Windows'
SystemTime and panicked before timestamp() ran, failing the Windows
test job. Build it with checked_add and only assert where it exists.

* Keep FormCalc dates exact past chrono's range

MAX_DAYS accepts day numbers up to 1e8 (years past 270000), but NaiveDate
stops near ±262143, so Num2Date(99000000) and Format fell back to
1900-01-01. days_from_civil, civil_from_days and days_in now have chrono
convert within the date's 400-year Gregorian cycle and add whole cycles
back (via i128), which gives the pre-chrono results for every year. Tests
cover accepted inputs past chrono's range on both sides of the epoch,
through Num2Date and Format, with values from the old formula.

* Bump rustls-webpki and webpki-root-certs for RUSTSEC-2026-0382/0383

rustls-webpki 0.103.15 -> 0.103.16 and webpki-root-certs 1.0.9 -> 1.0.10
(both semver-compatible, lockfile only) drop the distrusted emSign
intermediates and root. Only these two entries change; cargo deny check
advisories passes. Upstream main fails the same check.

* logging/cos/sign/combine/demo: keep extended-year dates, no epoch fallback

For consistency with the stricter no-epoch-fallback rule now agreed across the sibling
chrono PRs (wordcraft#3427, filmcraft#2662): `DateTime::from_timestamp(..).unwrap_or_default()`
changes a timestamp the old code converted past chrono's year 262143 range — it collapses
to 1970-01-01 instead of the real proleptic-Gregorian date. The FormCalc Num2Date path was
already fixed (FredApps approved); this applies the same fix to every remaining conversion.
Each site uses the 400-year Gregorian cycle (146_097 days) with chrono as the only calendar
logic: chrono converts the day within one cycle, whole cycles carry in the year (i128,
saturated into i64). PDF/ASN.1 format-specific year handling is kept exactly as the old code
had it. Verified the cycle result equals the old formula across a wide range and at the extremes.

- apps/pdfcraft/src/logging.rs `timestamp`: cycle `civil_from_days(u64)`; pre-1970 epoch clamp
  and ms/time-of-day format kept. Pins: +10_000_000_000_000 s -> 318857-05-20T17:46:40.000Z
  (was 1970); checked_add u64::MAX/2 s -> 292277026596-12-04T15:30:07.000Z (was epoch).
- crates/cos/src/writer.rs `pdf_date` (i64): cycle converter, no year clamp (old code wrote `y`
  as-is, so a negative year keeps its sign). Pins: pdf_date(10_000_000_000_000)="D:3188570520174640Z",
  pdf_date(-10_000_000_000_000)="D:-3149180813061320Z".
- crates/sign/src/der.rs `Time::from_unix` (i64): cycle converter; the `year` field is a u32, so
  the year is cast `as u32` (wrapping) exactly as the old code did — ASN.1 year width preserved
  byte-for-byte. Pins: from_unix(10e12).year=318857, from_unix(-10e12).year=4_294_652_378,
  from_unix(i64::MAX).year=219_250_468, from_unix(i64::MIN).year=4_075_720_767.
- crates/ui-egui/src/combine_ui.rs `utc_stamp` (u64): cycle converter; pre-1970 epoch clamp kept.
  Pins: utc_stamp(10e12)="318857-05-20 17:46 UTC", u64::MAX/2 s="292277026596-12-04 15:30 UTC".
- xtask/src/demo_pdf/pdf.rs `Stamp::from_unix` (i64): cycle converter, no year clamp. Pins:
  from_unix(10e12).iso="318857-05-20T17:46:40Z"/.pdf="D:3188570520174640Z",
  from_unix(-10e12).iso="-314918-08-13T06:13:20Z".

cos/sign/xtask built, tested (pdf_dates_are_utc_and_byte_identical, der::tests::times,
stamps_round_trip), fmt and clippy clean. pdfcraft-ui-egui and the pdfcraft app can't link
here (unrelated LLVM intrinsic bug in the rten-gemm dependency, 1.98.1), so their logging and
combine_ui functions + tests were copied verbatim into a scratch crate with chrono 0.4.45 and
pass there; fmt --check clean on all five packages. CI builds these on all platforms.

* Don't build a year-318857 SystemTime unchecked in the logging test

Windows' SystemTime only reaches about year 30828, so
UNIX_EPOCH + Duration::from_secs(10_000_000_000_000) panicked before
timestamp() ran and failed the Windows test job. Build it with
checked_add and assert where the platform can hold it. The year-10000
case fits everywhere and stays unconditional.

* Name the 400-year range extension as the one exception to the time rule

The rule said never to hand-roll calendar math, but the range fix
(shifting by whole 400-year Gregorian cycles so dates past chrono's year
range keep their old output) is cycle arithmetic, so the rule and the code
disagreed. The rule now names that exception: the library still computes
month, day and time, and only whole cycles are carried in the year.

* Say the library computes month and day; time-of-day is plain arithmetic

Narrows the range-extension wording: the date library computes the
calendar fields, and splitting seconds into hours, minutes and seconds
is ordinary arithmetic, which is what the code does.
2026-10-21 19:36:46 -04:00
Eric Kaden 6a8ea287aa M6: doc comments on the functions the formattedValue change touches 2026-10-20 23:37:21 -04:00
Eric Kaden 7176ebde94 M6: XFA formattedValue shows a date in the field's display picture
Fields keep their <format><picture>. A date display picture turns the
ISO value into its pattern for scripts' formattedValue (JavaScript and
FormCalc), so date arithmetic on formattedValue works as forms expect.
Once a script sets the value, formattedValue gives that value. Number
and text display pictures still give the raw value.
2026-10-20 23:29:08 -04:00
NetterSilverandClaude Haiku 5.5 3246587e85 Return empty WordNum result when cents rounding carries to 1e12
Found while testing crates/js/src/formcalc.rs:2024-2050 (word_num)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 17:38:34 +00:00
Eric Kaden b6cd6b44ca M6: doc comments for the functions around this change 2026-10-20 09:26:34 -04:00
Eric Kaden a0ae8a3996 M6: doc comments for the functions this change touches 2026-10-19 23:43:02 -04:00
Eric Kaden 032febca2f M6: doc comments for the functions this change touches 2026-10-19 23:42:56 -04:00
Eric Kaden c90afe54cf M6: say why a form's Save opens Save As 2026-10-19 22:22:03 -04:00
djmushin 0ba01a0557 M6: optimize AcroForm JavaScript snapshots and diffs 2026-10-19 22:03:49 -04:00
Eric Kaden 9366af3bad M6: side panels have fixed automation ids, and the parity note says where Print works 2026-10-19 22:01:10 -04:00
Eric Kaden e8eb840ec5 M6: form buttons show the side panels (execMenuItem ShowHide…) 2026-10-19 20:59:14 -04:00