Commit Graph
40 Commits
Author SHA1 Message Date
6427357fcb Forms: date fields name months in the date language, not always English (#5303) (#5464)
* Forms: date fields name months in the date language, not always English (#5303)

`AFDate_FormatEx("dd-mmm-yy")` wrote "18-Oct-26" in an Italian interface,
where a localized Acrobat writes "18-ott-26". Form date formats,
`util.printd` and `util.scand` now take their month and weekday names
from the date language (Preferences > Date format > Language, which
follows the interface language until one is picked), and still read
English names typed in. The names are process-wide, so their test runs
in its own binary.

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

* Forms: dates read back in every date language (#5303)

Trying every date language showed what a field wrote not always reading
back: names holding digits ("10月"), spaces ("tháng 10"), dots ("ม.ค.")
or combining vowel signs (Thai, Hindi, Telugu) fell apart word by word,
and Italian, Spanish, Romanian and Albanian share some short weekday and
month names ("mar"). The language's names are now found whole in the
text first, the longest at each place, and read as their English names;
the format's order of `mmm` and `ddd` settles a shared name. Both
AFDate parsing and util.scand do this, on text up to 1 KB. A test reads
back every language, each name format, and hostile text.

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

* Forms: date names no field font can draw are drawn in English (#5303)

With the names in the date language, a Russian dd-mmm-yy field drawn in
Helvetica showed "18-????.-26": no /DR font held "окт." and the WinAnsi
stand-in drew each letter as ?. The same held for Japanese, Chinese,
Greek, Arabic, Thai and others, and for Latin names outside WinAnsi
(Czech "říj"). Before, the names were English and always drew. An
AFDate/AFTime field now formats its value again with English names for
a widget whose fonts can't draw the localized text; a custom Format
script is run again with util.printd writing English names for such a
widget, and its result kept only when it draws whole. A field whose
font holds the names keeps them, and scripts otherwise still print the
date language.

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

* Forms: an English weekday before the month keeps the month (#5303)

With Italian dates, "Tue 17 Mar 2026" in a "ddd d mmm yyyy" field read
as no date: the language's names were found in the text, but not
English ones, so "Tue" left the format's weekday unfilled and "Mar",
which Italian shares between Tuesday and March, was taken as the
weekday. Both AFDate parsing and util.scand lost the month, and
Spanish, Romanian and Albanian ("mar") did the same. English names are
now found too and fill their field of the format as localized ones do.
A test reads English and mixed weekdays before the month in those
languages.

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

* Forms: an English date run is drawn even when it prints the value (#5303)

A Helvetica field storing "18-Oct-26" whose Format script prints it
again as dd-mmm-yy still showed "18-???.-26" in Russian. The English
run printed "18-Oct-26", but it was dropped for equalling the stored
value, which was how a failed run was told apart: a failing script
handed back the value unchanged. The English run now says whether it
ran (`None` when the script failed or the runner can't write English
dates), and what it made is drawn whenever it draws whole. A test
reprints the stored value under Russian, and checks that a failing
script keeps its text and is reported undrawn.

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

* Forms: a short weekday typed without its dot is the weekday (#5303)

With French dates, "mar 6 janv 2026" in a "ddd d mmm yyyy" field read
as no date through util.scand, and "mar 06/01/2026" in "ddd dd/mm/yyyy"
through AFDate too. French writes Tuesday as "mar.", which a name
search only found with its dot; since English names are found as well,
the English "Mar" (March) was the only name of that length, so the
weekday became a month. Romanian "mar" did the same. A short name
ending in a dot is now also found typed without it, as the same kind of
name, so the format's order of name fields decides between it and an
equal name of the other kind. Both copies of the name search change. A
test reads French and Romanian weekdays typed without their dot.

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

* Forms: a shared name is the month when no weekday is typed (#5303)

With Italian dates, "17 mar 2026" in a "ddd d mmm yyyy" field read as
no date, nor did "mar 17, 2026" in "dddd, mmmm d, yyyy". AFDate leaves
weekdays out of what it reads (they are shown, not typed), but the name
search still expected the format's weekday first, so "mar", which
Italian shares between Tuesday and March, filled it and left no month.
Spanish and Albanian "mar" and Albanian "sht" (Saturday, September) did
the same, and the keystroke check refused those dates. Where such a
read finds no date, the names are now read again with no weekday
expected, so the shared name is the month; a typed weekday still comes
first ("mar 17 mar 2026"). util.scand reads its fields in order and
needs the weekday, so it is unchanged. A test types those dates with the
weekday left out.

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

* Forms: Turkish names typed in capitals are read (#5303)

With Turkish dates, "1 MAYIS 2026" and "1 EKİM 2026" in a d mmmm yyyy
field read as no date through AFDate and util.scand, and "SALI 6 OCAK
2026" through util.scand. Names were compared lower-cased, which turns
I into i, not the dotless ı of "Mayıs" and "Salı", and İ into i with a
combining dot above, which "Ekim" doesn't have. Names and typed text
are now folded alike, the capital I and the dotted and dotless i all as
i and the combining dot dropped, one piece for each char so positions
in the text stay aligned: in both copies of the name search, the AFDate
month reader and util.scand's name matcher. English reads as before. A
test types Turkish names in capitals and English ones as a check.

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

* Forms: Greek names typed in capitals are read again (#5303)

Folding names char by char turned a capital Σ into σ, so "ΙΑΝΟΥΆΡΙΟΣ"
no longer matched "Ιανουάριος", whose last letter is the final ς. The
fold now makes ς a σ on both sides, in the forms and JS parsers alike.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-05 16:12:04 +01:00
Eric Kaden 21f6c29d3e M6: form script messages keep their title, icon and buttons, and every one is shown (#4293, #4294) (#4306)
* M6: form script messages keep their title, icon and buttons, and every one is shown (#4293, #4294)

* M6: a form script message waits for a notice the toast already shows

* M6: form script messages past the queue's room are counted and reported

* M6: a sentence break in the merged parity note

* M6: an object that names no parameter is a message's text, as a String object or a caught error

* M6: the count of left-out script messages is said again if another notice replaces it before its time

* M6: a full stop between two sentences of the FormCalc parity note

* chore: re-run CI (a frame-budget timing test missed on a shared runner)
2026-10-28 17:46:11 -04:00
aiongg 315454d3a9 Merge PR #2648 at its updated head
# Conflicts:
#	crates/engine/src/js.rs
2026-10-24 07:21:13 +00:00
PerchAnton 1732f8eb7e M12 #2589: preserve XFA script policy with current JavaScript context 2026-10-24 09:39:40 +03:00
aiongg 9705e7a6c1 Merge track r3-t03 2026-10-24 06:39:33 +00:00
aiongg 52f41f50d1 Integration: cargo fmt 2026-10-24 06:34:49 +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 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
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
Marco Arnulfo c5b0e6aa61 M6: Actions tab: replacing a trigger's first action keeps its chain, and the row shows it (#4006)
The actions chained after a trigger's first one (/Next) are kept
whatever replaces it, not only another script, and the row reads
"…, then N more actions". Edit is disabled on every row while a
script is open, so it can't be overwritten.
2026-10-23 21:02:47 +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
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 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
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 f2f86455dd fix(engine): read long underscore runs in one pass
Word assembly checked whether the whole word so far was underscores for
every glyph it added, so a long run of underscores on one line took
quadratic time. The underscore state of the current word is kept as it
grows.
2026-10-22 18:02:33 +00:00
PerchAnton c5279baf35 M6 PR #2648: retain active-XFA script isolation with current main 2026-10-22 20:21:39 +03: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
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 123b214180 Merge r2 track t10: xfa 2026-10-22 02:21:06 +00:00
aiongg ca2e7f8ffd Merge PR #2840: M6: detected form fields get no border or fill
crates/engine/src/js.rs: auto_detect_fields keeps main's comb and turn handling, builds props with no border and no fill for every field, and pushes SetFieldProps unconditionally (the review's fix)
parity/acrobat-features.toml: form.detect-fields keeps main's comb evidence and notes and adds the no-border test and sentence
2026-10-22 01:47:29 +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
djmushin 0ba01a0557 M6: optimize AcroForm JavaScript snapshots and diffs 2026-10-19 22:03:49 -04:00
Eric Kaden 74326b455c M6: a field's own script may not open Save As 2026-10-19 21:02:37 -04:00
Eric Kaden e8eb840ec5 M6: form buttons show the side panels (execMenuItem ShowHide…) 2026-10-19 20:59:14 -04:00
PerchAnton 52cdb9260c M12: retain product notes while integrating current main 2026-10-18 16:09:57 +03:00
PerchAnton be6a66dd79 M12: retain product notes while integrating current main 2026-10-18 16:00:08 +03:00
Marco ArnulfoandBrandon Thomas 50f261d70c M6: detect a row of comb boxes as one comb text field (#2111)
* M6: detect a row of comb boxes as one comb text field (fixes #1887)

* M6: keep empty tables of wide cells out of comb detection (#1887)

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 03:50:00 -04:00
boneylandandClaude Opus 5.5 bf2eb470ed M6: detected form fields get no border or fill
Prepare a form ▸ Detect form fields places each field on a line or box the
page already draws, but every new widget got a grey /MK /BC and an opaque
white /MK /BG, so the fill hid the printed form underneath. Detected fields
now clear both in the same undoable step; fields drawn by hand keep the
defaults.

Refs #294, #2831.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 18:59:09 +08:00
PerchAnton ff62683ff8 M12: skip PDF container scripts during active XFA layout (#2589) 2026-10-15 22:18:58 +03:00
PerchAnton f06bebd520 M12: dispatch repeated XFA print buttons by their own field (#2572) 2026-10-15 20:08:05 +03:00
alexanderalber 5b220eb886 M6: detect form fields on scanned pages (#1721) (#1722)
Field detection read only vector data: text-layer words and drawn
rectangles and lines. A scanned form is a single picture, so it found
nothing there.

A page that an image covers at least half of, and whose content draws
no lines, is now rendered at 144 dpi and its shapes are read from the
pixels (pdfcraft_forms::detect::raster): ink against a local mean,
long thin runs as lines, enclosed rectangular patches of paper as
boxes, the empty band of a box with a small printed label as its
writing area, and the open-ended horizontal lines as rules. Labels come
from the text layer, else from OCR when the models are installed;
without either the fields get default names. Detection works in the
displayed frame, so a scan stored sideways reads like any other, and
fields on a turned page get /MK /R so typing reads upright.

generated with Claude Code
2026-10-15 02:21:42 -04:00
11ffedcc98 XFA: run the forms' JavaScript: calculations, validation, rows, visibility (#60) (#230)
* M12: run XFA forms' JavaScript: calculations, validation, rows, visibility (#60)

Laid-out XFA forms had their fields but none of their behaviour: totals
didn't compute, "Add row" buttons did nothing, and subforms a check box
should reveal stayed hidden.

The js crate gains the XFA scripting object model as native boa objects
over a snapshot of the form tree: xfa.form navigation by name, SOM
resolution (absolute, relative with the containing-subform search,
descendants, indexes and wildcards), rawValue/presence/access, instance
managers (_name, addInstance, removeInstance, setInstances, count),
xfa.host (messageBox, resetData, print, setFocus, gotoURL), xfa.layout
page numbers, xfa.event, app, console and util, plus unqualified sibling
names as XFA resolves them. Scripts run with `this` bound to the node and
yield their completion value; everything they change or ask for comes
back as effects.

The xfa crate builds the live form tree (instances from the data, values,
presence and access with overrides) and the event table from the
template, keeps presence and access overrides on the AcroForm
(/PCXfaOverrides) so undo and reopening preserve them, adds and removes
row instances in the datasets packet through the existing merge
pipeline, and lays the form out again on demand.

The engine runs initialize and calculate scripts on open (an appended
revision, nothing dirty), exit, validate and calculate after a field
changes (a failing validate shows its message and keeps the value, as
Acrobat does), and click scripts for buttons through run_javascript, so
the app's buttons and the js_run tool work unchanged. Values a script
sets go to the fields and the data at once; rows and visibility changes
re-lay the form out. All of it is one undo step. JavaScript off turns it
off. FormCalc scripts are recognised and reported, not run.

Bounds: script length and nesting as before, loop and recursion limits,
at most 1000 instances added per run, 2000 scripts and 50 re-layouts per
event; a calculate script that adds rows, or a click script looping on
addInstance/setInstances, ends quickly with a bounded form (tested).

Checked on IRCC's IMM 5669: opens with its page-number scripts, the Print
button's xfa.host.print runs through js_run, fill and save keep the
original bytes.

* M12: Save and SaveAs named actions run the file commands (#60)

XFA forms' Save buttons are app.execMenuItem("SaveAs"), which the layout
turns into a SaveAs named action; the shell answered it with "the SaveAs
action isn't supported yet". Named Save and SaveAs now run file.save and
file.save_as, like Named Print opens the print dialog.

The buttons test covers Save against a file on disk (SaveAs opens the
native dialog, which a headless test must not).

* M12: bound XFA form scripts against hostile forms (#60)

Review fixes for the XFA scripting PR (#230):

- Effects: values, presence and access set again on the same object merge
  (last wins, behind order-dependent effects); 10k effects, 100 message boxes
  and 1000 console lines per script and per event, reported when hit. An
  event's data writes are kept in memory and written as one rewrite of the
  datasets packet; later writes in the same edit replace that stream in place.
- form_tree stops at 200k objects and says so; forms without scripts build no
  live form and run nothing.
- Only click scripts may print, save, open links or move the focus; others are
  noted in the console. Open-time messages and errors show right after open.
- Lower loop limits for initialize/calculate/validate, a time budget per event
  after which remaining scripts are skipped and reported, and a per-script time
  limit after which a runaway script is abandoned and the document's scripts
  turned off.
- What open-time scripts change is noted in the XFA warnings.
- A document's Named /Save no longer writes the file on click (SaveAs opens
  the Save As dialog, as a script's execMenuItem does).
- XFA click scripts are no longer written as /S /JavaScript actions: the
  button carries /PCXfaClick and runs by SOM path. Private keys documented.

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

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 04:16:54 -04:00
Brandon ThomasandClaude Opus 5.5 d3db99818f Rename PrintCraft to PdfCraft (#174)
The app, crates, binaries, bundle id, packaging, icons, screenshots and docs are now
PdfCraft / pdfcraft (repo storytold/pdfcraft). On first launch the desktop app moves the
PrintCraft settings and crash-recovery folders to the new name, and both apps read settings
saved under the old storage key, so upgrades keep recent files, preferences and unsaved work.
The signing test fixtures keep their PrintCraft subject names (they are binary).

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 16:03:57 -04:00
Brandon ThomasandClaude Opus 5.5 c12b795ce5 M12: Compare files (new compare crate): word-level text differences, Compare panel with shading on the new file, report PDF, differences as comments; doc_compare, doc_compare_report, doc_compare_mark tools
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 05:31:18 -04:00
Brandon ThomasandClaude Opus 5.5 aa194686f1 M6: Prepare a form detects fields (underscore blanks, rules, boxes, check squares) and names them from their labels; form.detect, form_detect_fields
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 05:21:01 -04:00
Brandon ThomasandClaude Opus 5.5 620ef4fcad M6: Field Properties ▸ Actions tab (six triggers, JavaScript/link/reset/menu/page/show-hide/submit actions); form_actions, form_set_actions tools; signing UI tests get their own temp folders
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 05:08:28 -04:00
Brandon ThomasandClaude Opus 5.5 06f8d73ec7 M6: Acrobat JavaScript: sandboxed boa engine with the forms object model (printcraft-js); custom keystroke/validate/calculate/format scripts, button scripts, document JavaScripts, JavaScript console (⌘J), Preferences ▸ Enable JavaScript; js_run, js_document_scripts, js_set_document_script, form_set_script, js_enabled tools
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 04:41:47 -04:00