Commit Graph
54 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
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 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 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
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 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 ae9cd9f623 Merge PR #3004: Zero-pad required integer digits in FormCalc Format() 2026-10-22 01:45:13 +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
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
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
Eric Kaden 86e44dc6d5 M6: util.scand reads dates as another viewer does 2026-10-19 16:36:47 -04:00
NetterSilverandClaude Haiku 5.5 8d6254aa0b Render weekday letters in FormCalc date pictures (#3321)
Found while testing crates/js/src/formcalc.rs:1929-1957 (format_date), with DateFmt returning "EEEE, MMMM D, YYYY" at :2333

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-18 17:06:18 -04:00
NetterSilverandClaude Haiku 5.5 31373819f2 Zero-pad required integer digits in FormCalc Format()
Found while testing crates/js/src/formcalc.rs:2240-2276 ("format" builtin, number branch)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-18 16:20:32 +00:00
NetterSilverandClaude Haiku 5.5 5157e0421b Keep seconds in FormCalc Time2Num/IsoTime2Num for ISO 8601 times
Found while testing crates/js/src/formcalc.rs:2348-2352 ("time2num" | "isotime2num")

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-17 02:24:39 +00:00
NetterSilverandClaude Haiku 5.5 bafb948226 Round FormCalc Str and Format exact ties away from zero
Found while testing crates/js/src/formcalc.rs:2169 (Str) and :2258 (Format number picture)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 22:19:58 +02:00
NetterSilverandClaude Haiku 5.5 0d864e2e31 Reject impossible dates such as Feb 30 in FormCalc Date2Num and Parse (#2388)
Found while testing crates/js/src/formcalc.rs:1916

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-15 02:58:25 -04:00
NetterSilverandClaude Haiku 5.5 c97ca226e6 Fix util.printd panic on an escaped multi-byte character (#2386)
Found while testing crates/js/src/lib.rs:785

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-15 02:58:15 -04:00
ysrdevs 29f4edf5be XFA: a script's time starts when its context is ready, and a value reaches every field bound to its data node (#1589)
Two follow-ups the maintainer asked for after #1355.

The script session's worker now says when the engine is ready for the
script it was sent (its JavaScript context built; FormCalc at once),
and the script's time limit runs from then, with the engine's own
start limit before it, as the one-shot path always did: building a
context is not charged to the script, which matters on a busy machine.

A field inside an area shares its data node with a field of the same
name outside it (areas are left out of data paths). The in-place
refresh of the live form now follows the data path through the tree
and gives every field bound to the node the value the tree builder
would, each by its own template field (an exclusion group there means
a rebuild), and the engine's value setter, with an index of widgets by
data node, gives every widget bound to the node the value by its own
kind, hidden fields included, writing the data whenever the node's
text differs. The script's time now also starts after its host and
globals are set up. A stale parity note (choosing a picture for an
image field, delivered in #1175) is removed.
2026-10-13 00:10:22 -04:00
ysrdevs 4b45fc9cb4 XFA: one script thread per event, and the live form kept up to date in place (#1355)
* XFA: one script thread per event, and the live form kept up to date in place

A form with hundreds of calculate scripts used to spend its open-time
budget on set-up: every script got a thread of its own, and the engine
dropped its live form after every value a script settled, rebuilding
the whole tree for the next script.

The js crate gains xfa_session::XfaSession: the scripts of one event
run on one thread (with the script stack), each in a fresh JavaScript
context or FormCalc interpreter on a copy of the form as the engine
holds it then, so scripts share nothing, a script that fails halfway
leaves nothing behind, and what a script changed reaches the next one
only through the engine. A script past its time limit is abandoned on
the thread and the session is dead from then on; a fault in the engine
(a panic) loses only that script, the thread is replaced. On wasm the
scripts run inline, as before.

The engine's runner keeps one session per event and, for a value, now
refreshes the one field in its live form in place (xfa::refresh_value,
computing the value as the tree builder would: saved values, template
defaults) instead of rebuilding the tree; rows, presence, access,
resets, relayouts and data rewrites still rebuild it. Under test, the
live form is compared with a fresh build before every script and at
the end of every event, and a difference ends the test binary (a panic
would be caught by the engine's guard and turned into a script error).

210 calculate scripts (one per row of 10 sections x 20 rows, plus a sum
per section), debug build, instrumented inside the engine: the script
event on open 495 ms -> 204 ms (of which live-form rebuilds 217 ms ->
0), on a change 300 ms -> 172 ms; through the tools, layout included,
open 1.27 s -> 0.97 s and a change 0.44 s -> 0.22 s. The rebuild cost
removed grew with form size times script count.

* CI: the GoToR tests' case lists are only grown on Unix, so Windows must not warn on their mut
2026-10-12 05:39:49 -04:00
a7e24b9512 M12: XFA script time limits start when the engine is ready (#1081)
* M12: XFA script time limits start when the engine is ready

An XFA script's wall-clock limit (1 s for scripts that run unasked, such
as initialize and calculate) also counted the engine's start-up: the
script thread, a new boa Context, and for the first script in a process
the engine's own one-time set-up (~60-170 ms when idle, shared by every
script starting at the same moment). On a busy machine a trivial
initialize script could pass 1 s, be abandoned, and so turn all of the
form's scripts off, with the error only in the JavaScript console.

That made two ui-egui xfa.rs tests flaky
(xfa_buttons_run_their_scripts_in_the_app,
messages_from_scripts_run_on_open_show_right_away): under full CPU load
25 of 40 runs of the test binary failed, and none of 40 with this
change.

- run_within: the script calls `started` once the engine is ready, and
  the time limit runs from then. Start-up has a cap of its own (10 s),
  so a caller still never waits forever.
- run_here: a once-per-process warm-up script takes the engine's first
  use, so the first form script's timed part drops from ~52 ms to under
  ~11 ms.
- FormCalc (no engine to start) signals at once, as before.
- Tests: a slow start doesn't abandon a script; the script's own time,
  and start-up, are still capped. The UI tests print the script console
  when they fail.

Runaway scripts are still abandoned at the same limits
(runaway_xfa_calculations_at_open_end_quickly_with_a_report).

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

* Add arcanii to the contributor names

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-11 11:58:28 -04:00
Ikki NishiharaandClaude Sonnet 5.5 1b6e144c57 JavaScript: limit util.printf widths and output, and array arguments (#770)
util.printf accumulated a conversion's width and precision with unchecked
arithmetic and no maximum, and its output had no bound; the array
arguments of resetForm and the field value/colour setters were read for
as many items as the array's length says, which a sparse array makes
free. Saturate the numbers and refuse widths and precisions above 4096,
output above 1 MiB and arrays longer than 2^20 with a script error,
before anything is allocated from them.

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-10 15:47:05 -04:00