Commit Graph
388 Commits
Author SHA1 Message Date
Combiler01 dea68e6350 Fixes Suggest by Reviewers 2026-10-23 00:21:21 +05:30
Combiler 5c8db57e5c Merge branch 'storytold:main' into main 2026-10-22 17:32:38 +00:00
aiongg 5dc64face0 fix(automation): keep page text from tools when copying is not allowed
text_lines returned a copy-restricted document's lines, ocr_recognize returned
the words it recognised, and text_edit on a paragraph echoed the paragraph's
own text, all without checking the copying permission that the other text
tools check. text_lines is refused like them; recognising and restyling still
work with permission to change the document, and leave the text out.
2026-10-22 13:18:26 -04:00
Combiler01 7d2b02633c Merge remote-tracking branch 'upstream/main' 2026-10-22 21:01:36 +05:30
aiongg 9526363152 Build each crate's integration tests as one binary (#4087)
* Build each crate's integration tests as one binary

Every tests/*.rs file is its own executable that links the whole crate
graph. Move each crate's test files into tests/it/ as modules of one
tests/it/main.rs, for apps/pdfcraft, apps/pdfcraft-cli, automation, cos,
crypt, engine, render, sign and ui-egui. ui-egui's ui_group binary and
the support modules move into tests/it/ too. Crates with a single test
file keep it. The test executables go from 150 to 52, and every crate
runs the same number of tests as before.

ui-egui perf keeps its own binary (own process): its frame-time budgets
would charge each measurement for the other tests running beside it.

What the move needs:
- include_str!/include_bytes! and #[path] paths gain one "../".
- ui-egui: one GPU lock in tests/it/main.rs replaces the five per-file
  ones (content, document_links, editing, fill_sign, view), so one
  process creates one wgpu device at a time. The drop-line test in ui.rs
  and the screenshot blocks behind PDFCRAFT_*_SHOT(S) and
  CRAFT_UI_DOCKING_DIR, which render without holding it, take it too.
- pdfcraft winit_wayland_scroll: the vendored winit source it compiles
  names crate::event, so that shim lives in main.rs.
- parity evidence names the new paths.

* Name the one-binary test paths in docs and comments

- READMEs, docs, ATTRIBUTION and source comments name tests/it/<file>.rs.
- The oracle README's example filters with --test it encryption::qpdf_agrees.
- pdfcraft's GPU lock comment points at the UI tests' shared lock in
  crates/ui-egui/tests/it/main.rs.
2026-10-22 11:28:58 -04:00
Combiler01 4d93503937 Merge remote-tracking branch 'upstream/main'
# Conflicts:
#	ATTRIBUTION.toml
#	crates/automation/src/tools.rs
#	crates/automation/tests/automation.rs
#	crates/edit/src/images.rs
#	crates/edit/src/lib.rs
#	crates/edit/src/tests.rs
#	crates/engine/src/lib.rs
#	crates/ui-egui/src/create_ui.rs
#	crates/ui-egui/src/edit_text_ui.rs
#	crates/ui-egui/src/editing.rs
#	crates/ui-egui/src/i18n/es.tsv
#	crates/ui-egui/src/i18n/pt-br.tsv
#	crates/ui-egui/src/i18n/vi.tsv
#	crates/ui-egui/src/lib.rs
#	crates/ui-egui/tests/content.rs
#	crates/ui-egui/tests/editing.rs
2026-10-22 13:32:03 +05:30
Combiler01 67f1a57f08 Merge remote-tracking branch 'upstream/main'
# Conflicts:
#	ATTRIBUTION.toml
#	crates/ui-egui/src/content_ui.rs
#	crates/ui-egui/src/i18n/ar.tsv
#	crates/ui-egui/src/i18n/bg.tsv
#	crates/ui-egui/src/i18n/cs.tsv
#	crates/ui-egui/src/i18n/de.tsv
#	crates/ui-egui/src/i18n/el.tsv
#	crates/ui-egui/src/i18n/es.tsv
#	crates/ui-egui/src/i18n/fr.tsv
#	crates/ui-egui/src/i18n/hu.tsv
#	crates/ui-egui/src/i18n/it.tsv
#	crates/ui-egui/src/i18n/ja.tsv
#	crates/ui-egui/src/i18n/kk.tsv
#	crates/ui-egui/src/i18n/lt.tsv
#	crates/ui-egui/src/i18n/pl.tsv
#	crates/ui-egui/src/i18n/pt-br.tsv
#	crates/ui-egui/src/i18n/ru.tsv
#	crates/ui-egui/src/i18n/sl.tsv
#	crates/ui-egui/src/i18n/te.tsv
#	crates/ui-egui/src/i18n/tr.tsv
#	crates/ui-egui/src/i18n/uk.tsv
#	crates/ui-egui/src/i18n/vi.tsv
#	crates/ui-egui/src/i18n/zh-hans.tsv
#	crates/ui-egui/src/i18n/zh-hant.tsv
#	crates/ui-egui/src/lib.rs
#	crates/ui-egui/src/panels.rs
2026-10-22 11:59:39 +05:30
aiongg 472717fcd7 Merge upstream main 88dad98dd into next
# Conflicts:
#	ATTRIBUTION.md
#	ATTRIBUTION.toml
#	crates/engine/src/dates.rs
#	crates/ui-egui/src/i18n/ar.tsv
#	crates/ui-egui/src/i18n/bg.tsv
#	crates/ui-egui/src/i18n/cs.tsv
#	crates/ui-egui/src/i18n/de.tsv
#	crates/ui-egui/src/i18n/el.tsv
#	crates/ui-egui/src/i18n/es.tsv
#	crates/ui-egui/src/i18n/fr.tsv
#	crates/ui-egui/src/i18n/hu.tsv
#	crates/ui-egui/src/i18n/it.tsv
#	crates/ui-egui/src/i18n/ja.tsv
#	crates/ui-egui/src/i18n/kk.tsv
#	crates/ui-egui/src/i18n/lt.tsv
#	crates/ui-egui/src/i18n/mod.rs
#	crates/ui-egui/src/i18n/pl.tsv
#	crates/ui-egui/src/i18n/pt-br.tsv
#	crates/ui-egui/src/i18n/ru.tsv
#	crates/ui-egui/src/i18n/sl.tsv
#	crates/ui-egui/src/i18n/te.tsv
#	crates/ui-egui/src/i18n/tr.tsv
#	crates/ui-egui/src/i18n/uk.tsv
#	crates/ui-egui/src/i18n/vi.tsv
#	crates/ui-egui/src/i18n/zh-hans.tsv
#	crates/ui-egui/src/i18n/zh-hant.tsv
#	crates/ui-egui/tests/fonts.rs
#	docs/localization-parity.md
#	docs/localization.md
#	docs/roadmap.md
#	parity/acrobat-features.toml
2026-10-22 05:22:09 +00:00
aiongg b6c815672e Integration: cargo fmt 2026-10-22 02:52:29 +00:00
aiongg 2c13fd9373 Merge r2 track t16: mixed: automation-mcp, crate:misc, crypt-security, export-convert, optimize, preflight-pdfa, save-io
# Conflicts:
#	ATTRIBUTION.toml
#	contributors/people.toml
#	crates/automation/src/comments.rs
#	crates/edit/src/tests.rs
#	crates/engine/src/tests.rs
#	parity/acrobat-features.toml
2026-10-22 02:23:58 +00: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 c00a8b7616 Merge r2 track t14: signatures
# Conflicts:
#	ATTRIBUTION.toml
#	crates/annot/src/tests.rs
2026-10-22 02:22:02 +00:00
aiongg 15f558aaa8 Merge r2 track t11: redaction, mixed: combine, compare, crate:edit, measure, ocr
# Conflicts:
#	ATTRIBUTION.toml
#	crates/automation/src/tools.rs
#	crates/edit/src/lib.rs
#	crates/ui-egui/tests/compare.rs
#	crates/ui-egui/tests/ui_group/marks.rs
2026-10-22 02:21:38 +00:00
aiongg 123b214180 Merge r2 track t10: xfa 2026-10-22 02:21:06 +00:00
aiongg 2363b0619b Merge r2 track t09: print
# Conflicts:
#	ATTRIBUTION.toml
#	crates/ui-egui/src/lib.rs
2026-10-22 02:21:06 +00:00
aiongg 69e755c439 Merge r2 track t08: fonts
# Conflicts:
#	crates/automation/src/tools.rs
#	vendor/README.md
2026-10-22 02:20:50 +00:00
aiongg a2c46a9298 Merge r2 track t06: annotations-comments
# Conflicts:
#	crates/automation/tests/automation.rs
#	crates/render/src/raster.rs
2026-10-22 02:19:23 +00:00
aiongg 8724f6b1a5 Merge r2 track t05: forms
# Conflicts:
#	crates/engine/src/tests.rs
#	crates/ui-egui/src/canvas.rs
#	crates/ui-egui/src/forms_ui.rs
#	docs/ui-parity.md
2026-10-22 02:18:46 +00:00
aiongg 2bd66fbe90 Merge r2 track t03: viewer-ui
# Conflicts:
#	crates/automation/tests/automation.rs
#	crates/engine/src/tests.rs
#	crates/ui-egui/src/content_ui.rs
#	crates/ui-egui/src/edit_text_ui.rs
#	crates/ui-egui/src/fill_sign.rs
#	crates/ui-egui/src/forms_ui.rs
#	crates/ui-egui/tests/editing.rs
2026-10-22 02:18:22 +00:00
aiongg 7bf122eea8 Merge r2 track t02: edit-content
# Conflicts:
#	crates/edit/src/tests.rs
#	crates/edit/src/text.rs
#	crates/ui-egui/src/canvas.rs
#	crates/ui-egui/src/edit_text_ui.rs
2026-10-22 02:17:34 +00:00
aiongg 4949724ec8 Merge PR #3875: M4: a new bookmark goes to where the reader is (#3865) 2026-10-22 01:48:54 +00:00
aiongg a447dd3db5 Merge PR #2731: Layers panel: Reset to Initial Visibility
Conflicts:
- ATTRIBUTION.toml: ours (sha256 lines only); hashes recomputed at the end of the track
- crates/engine/Cargo.toml: main's workspace chrono entry, plus the PR's pdfcraft-testkit dev-dependency
2026-10-22 01:48:51 +00:00
aiongg 88c21daaed Merge PR #2615: fix(xfa): enforce maxLength on rich-text fields
ROADMAP.md, docs/roadmap.md: all status lines and progress-log lines kept; M12 row takes both 'Done since' insertions.
parity/acrobat-features.toml: form.xfa evidence lists unioned, notes take both sides' insertions.
2026-10-22 01:48:32 +00:00
aiongg 9865f27d8c Merge PR #2619: fix(xfa): run click scripts for every repeated print button
ROADMAP.md, docs/roadmap.md: both status lines and progress-log lines kept; M12 row takes both 'Done since' insertions.
crates/automation/tests/automation.rs, crates/xfa/src/fixtures.rs: union of #2624's and #2619's tests and fixtures.
parity/acrobat-features.toml: form.xfa evidence lists unioned, notes take both sides' insertions.
2026-10-22 01:48:18 +00:00
aiongg 781a4d5e28 Merge PR #3622: Fix #3507: preserve content boundaries when merging image fragments
ROADMAP.md, docs/roadmap.md: the PR's status lines, log line, M11 note and revision rows applied onto main's
2026-10-22 01:48:04 +00:00
aiongg eb6a4a2d79 Integration: #1830 standards_remove_id is not the standards.pdfa command 2026-10-22 01:47:27 +00:00
aiongg 0f0d7dcb67 Merge PR #1830: M11: remove PDF/A or PDF/X identification (optimize.remove-standards-id)
ATTRIBUTION.toml: sha256 lines taken from main, recomputed after all merges
2026-10-22 01:47:19 +00:00
aiongg a456f516d9 Merge PR #2756: M7: a paragraph number keeps naming the paragraph text_paragraphs listed (#2516)
ROADMAP.md: kept both sides' progress-log lines.
crates/edit/src/lib.rs: re-export list is the union (TextSession from #3942; BlockKey, block_overlapping from #2756).
2026-10-22 01:47:18 +00:00
aiongg 3ba586fe31 Merge PR #2624: fix(xfa): reflow growable multiline fields after filling
crates/xfa/src/script.rs: template_field and named_in moved to crate::data in #3397; field_grows_with_text calls crate::data::template_field.
parity/acrobat-features.toml: form.xfa evidence lists unioned, notes take both sides' insertions.
2026-10-22 01:46:50 +00:00
aiongg 0859c9574d Merge PR #3042: fix(save): preserve destination extended attributes on macOS 2026-10-22 01:46:42 +00:00
aiongg 0b1cce39bc Merge PR #3781: Fill & Sign marks stay upright on rotated pages (#2392) 2026-10-22 01:46:17 +00:00
aiongg bb606504bb Merge PR #3561: M9: read .p7b/.p7c certificate bundles for trust import 2026-10-22 01:46:12 +00:00
aiongg f424cf0627 Merge PR #3311: fix(organize): prune named destinations without recursive calls
docs/roadmap.md: revision history keeps both sides' rows, newest first.
2026-10-22 01:45:57 +00:00
aiongg 47ecd2ebc7 Merge PR #3625: fix(forms): preserve comments across content streams
ROADMAP.md, docs/roadmap.md: union of the progress-log and revision lines
2026-10-22 01:45:49 +00:00
aiongg a0e8c2faa2 Merge PR #2609: fix(edit): draw the Cyrillic the Japanese faces lack with the bundled Inter face (#2593)
parity/acrobat-features.toml: edit.edit-text evidence and notes take both sides' additions
2026-10-22 01:45:35 +00:00
aiongg 15425d0d33 Merge PR #3721: M12: accept Identity CJK Unicode mappings in accessibility checks (#3673)
ROADMAP.md: progress log keeps both sides' lines.
docs/roadmap.md: revision history keeps both sides' rows.
2026-10-22 01:45:33 +00:00
aiongg 87f0f4bcbf Merge PR #3043: M3: layer_set shows or hides a layer, and page_render draws with the document's view settings (#2986) 2026-10-22 01:45:26 +00:00
aiongg 145a08ae96 Merge PR #3788: M5: drag a line's ends (and a polygon's corners) to change its length and angle
ROADMAP.md: union of progress-log lines.
crates/ui-egui/src/i18n/*.tsv (20 catalogs): union of appended keys.
2026-10-22 01:45:21 +00:00
aiongg 3116b5152a Merge PR #3187: Prevent overflow when rotating added images through automation 2026-10-22 01:45:20 +00:00
aiongg 29ad20342c Merge PR #2832: M7: Header & footer: shrink the page content out of their way (#2140)
ATTRIBUTION.toml: sha256 lines taken from the base side; recomputed after all merges.
2026-10-22 01:45:14 +00:00
aiongg b6fdb80cef Merge PR #3756: feat(edit): Header & Footer can be drawn in Times or Courier (#3754) 2026-10-22 01:45:09 +00:00
aiongg cb48f53a1e Merge PR #2715: fix(automation): tools on a file the viewer reads fewer pages of answer instead of panicking 2026-10-22 01:45:06 +00:00
aiongg 0b3321b990 Merge PR #3011: M12: the page side of a measuring scale takes a unit, so 1:50 is 1 mm = 50 mm (#2752) 2026-10-22 01:45:04 +00:00
aiongg d9d3a8279f Merge PR #2584: M10: Two-sided starts at Printer default, so the printer's own duplex applies (#2422)
ATTRIBUTION.toml: kept main's sha256 lines; hashes recomputed after the track.
2026-10-22 01:45:00 +00:00
aiongg d133dfbf75 Merge PR #1989: Edit images: rotate an image by any angle with a knob (#1940) 2026-10-22 01:44:58 +00:00
aiongg ee0b147a61 Merge PR #3728: Refuse redaction marks with no readable area instead of skipping them 2026-10-22 01:44:51 +00:00
aiongg 96a345ecb2 Merge PR #2851: fix(print): offer the US #10 envelope as a paper size (#2734) 2026-10-22 01:44:48 +00:00
aiongg 09e5232ff1 Merge PR #3411: Honor single-page redaction selections 2026-10-22 01:44:46 +00:00
d676fd44ea M6: Prepare a form ▸ Text field table: rows and columns of text fields as one edit (#3479)
* M6: Prepare a form ▸ Text field table: rows and columns of text fields as one edit

Drag an area with the Text field table tool and set it up in a movable
window: rows, columns, row and column spacing, the first row number,
column widths (draggable dividers, arrow keys once focused) and a name
pattern per column, with the table previewed on the page. Add fields adds
every cell as one undoable edit ("Add text field table").

- forms: `table` lays the table out in view space and names its cells. It
  refuses the whole table for a cell under MIN_FIELD_SIDE (now one
  constant) or a name with a period, used twice or already taken, and
  free_base picks the first free TableK for default names.
- engine: `field_table::edit` maps the cells onto the page, /Rotate and
  /UserUnit included, and checks their size again there.
- automation: `form_add_field_table`, with an end-to-end test.
- ui-egui: the window belongs to one page of one document and closes when
  that stops being the one prepared; Enter commits a number instead of
  adding the table; dividers between many columns no longer panic in
  f64::clamp. Strings in all 22 catalogs, and the Spanish engine-wording
  tests cover the table's mistakes.
- parity: form.multiple-copies is partial; copying an existing field into
  a grid is still missing.

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

* M6: text field table: refuse corners past the page's number range, run it by its command

Review follow-up on #3479.

- engine: a corner finite as an f64 but past f32's range came back from
  the page's f32 mapping infinite. With one such corner a side was
  infinite rather than NaN, so the cell passed and add_field refused it
  only once the edit was applied ("the field is too small"). The edit now
  refuses any corner that isn't finite on the page with the table's own
  reason, before anything is added.
- automation: form.add.text_table runs form_add_field_table through
  command_run, as comment.stamp runs stamp_custom.
- ui-egui: doc comments for the window's three remaining helpers.

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

* M6: text field table: close on document edits, lay out once per change, keep Escape for fields

Review follow-up on #3479 (benandez).

- The window belongs to the document as it was when it opened: it closes
  when the edit generation moves (a page rotated, moved or deleted, an edit
  undone), so a table set up for one page never lands on another or off it.
- The table is laid out and checked once per change, not several times a
  frame: the window and the page preview share one `Laid` (cells and the
  edit), and the preview draws only the cells in view, naming only those
  with room for a name.
- Escape in a field of the window leaves the field and keeps the setup; a
  second Escape closes the window.
- A table placed with a click is moved in from the page's edges, so all of
  it is on the page.
- `free_base` takes one pass over the names; `{seq}` is documented as
  counting from the first row number; `form_add_field_table` takes its
  names from the batch instead of laying the table out again; the
  unreachable `Dialog::FieldTable` arm says why it is there.

Each new test fails with its fix reverted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BfMGHQNgdq5yf5tKZHGR3z

* M6: text field table: drawn with its panel closed, the window opens Prepare a form instead of closing

With the tool picked and the Prepare a form panel closed, the form is
still prepared and a table can be drawn. Drawing sends the tool back to
Select, though, so nothing was prepared on the next frame, and the table
window, which lasts only while the form is prepared, closed itself at
once: the table couldn't be set up. Opening the window now opens the
Prepare a form panel it belongs to. Closing the panel while the window
is open still closes the window.

Found by CodeRabbit, which saw the preview stop drawing; the window
closing first was the larger effect. prepare.rs
a_table_drawn_with_the_panel_closed_opens_it_again fails without the fix
("the window stays open": (None, false)).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BfMGHQNgdq5yf5tKZHGR3z

* Drop the second generation binding the main merge left in document_area

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: aiongg <aiongtaigi@gmail.com>
2026-10-21 21:27:31 -04:00
ffaf312358 M6: Prepare a form ▸ Calculation order: a page to reorder, check and fix the order fields calculate in (#3733)
* M6: renaming a field renames it in the calculations that read it

A rename silently broke every formula that used the field: a sum dropped
it, notation read it as 0 and a script kept a stale value. set_props now
rewrites the name in each field's Calculate script, in the same edit:
AFSimple_Calculate field lists, simplified field notation (the BVCALC
comment and its translation) and getField calls naming it in one string
literal. The rest of each script is kept as written; names built at run
time, non-UTF-8 script streams and a name another field still has are
left alone, and a self-check keeps a script whose meaning would change.

Notation is read by one lexer shared by notation_js, eval_notation and
the rename. form_set_props returns formulas_updated; Field Properties
says how many calculations now use the new name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BfMGHQNgdq5yf5tKZHGR3z

* M6: form_set_props leaves the renamed field out of formulas_updated by object

The renamed field was matched by the name given, but set_props stores it trimmed and under
its parent's prefix. When the same call changed the field's own formula, formulas_updated
listed the field as one the rename had rewritten.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BfMGHQNgdq5yf5tKZHGR3z

* M6: calculation order: read, check, fix and set the order fields calculate in

A form's calculations run in its calculation order (/CO), which a field
joins when it gets a calculation, so a chain defined in the wrong order
shows stale values. calculation_order reads the order against the fields,
with what each formula reads (field lists, notation names, literal getField
names) and what is wrong: a field reading one that calculates later, a loop
(strongly connected components, found without recursion), a field /CO
leaves out, and /CO entries that calculate nothing. Fix order is a stable
topological sort that moves only what must move and leaves loops alone.
set_calculation_order writes /CO afresh; a name two fields share (a
malformed form) stands for the next of them in the current order.

Edit::SetCalculationOrder sets it in one undo step and recalculates, and
form_calculation_order reads, sets, moves one field or fixes the order
headlessly. An edited formula now keeps its field's place in /CO, a field
/CO lists twice calculates once, and recalculation runs each field by
object, so two fields sharing a name both calculate. The /CO code of the
Calculate tab, field scripts and recalculation goes through one place.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BfMGHQNgdq5yf5tKZHGR3z

* M6: Prepare a form ▸ Calculation order: a page to reorder, check and fix the order fields calculate in

The calculated fields in the order they calculate (/CO), each with its
formula and the value it shows, moved with Up/Down arrows (as Acrobat's Set
Field Calculation Order), Alt+Up/Down or by dragging. A card says which
fields read one calculated later, which read each other in a loop and which
/CO leaves out, and holds Fix order; a loop's card opens one of its
formulas. On the page, arrows show what the field in focus reads and what
reads it, with each linked field's step. The order is a page of the Prepare
a form panel, opened from its Fields tools, with a back arrow to Prepare a
form; opening it ends Preview and closes the page grid.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BfMGHQNgdq5yf5tKZHGR3z

* M6: form.calculation_order runs form_calculation_order headlessly

The command had no tool linked, so command_list showed none for it and
command_run refused it. form_calculation_order is now its tool: run without
a change, it reads the order.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BfMGHQNgdq5yf5tKZHGR3z

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: aiongg <aiongtaigi@gmail.com>
2026-10-21 20:30:58 -04:00