Commit Graph
1125 Commits
Author SHA1 Message Date
srt8hellcat2-ui db723fd087 M3: integrate page-edge shadow preference with current main (#1577) 2026-10-18 20:26:54 -04:00
vangel76andClaude Sonnet 5.5 f3b8654b23 Merge upstream/main into feat/image-rotate-snap
Resolve the ROADMAP.md progress-log conflict by keeping both sides' entries.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-19 02:08:53 +02:00
srt8hellcat2-ui ee29670cd9 M3: integrate two-paged launch flag with current main (#1354) 2026-10-18 19:32:39 -04:00
DjPeepjay fefdccc890 fix(viewer): preserve gap toggles in organize and comparison views
M3 / PR #3101: avoid stale organizer anchors and synchronize the active comparison gap choice across both panes through menu and control paths. Three regression tests fail before these fixes and pass after them. Document the gap helpers and test contracts.
2026-10-18 17:36:44 -05:00
DjPeepjay 7137c41f47 feat(viewer): add optional gapless continuous page display
M3: preserve reading position while joining page edges, with persisted defaults and opt-in UI control. Translate both labels in all 22 catalogs, update attribution, and cover catalog completeness with a regression test. Rebase PR #3101 onto current main while retaining navigation and rendering fixes.
2026-10-18 17:27:58 -05:00
Chiranjeevi U 4db6ac4ae2 M3: Accelerate coarse wheel scrolling (#1094)
* Viewer: accelerate coarse wheel scrolling (#1072)

Line/Page notches moved a fixed eased step, so a fast spin felt slow.
Accumulate one frame of coarse input per axis, scale by arrival rate
(1.0 idle, up to 6.0 spinning), and apply it directly like precise
touchpad input.

Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com>

* Viewer: add only the fast-spin surplus on top of egui smoothing

Single notches flow through egui untouched, so isolated input matches
the scroll speed preference exactly; page units are never boosted.

Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com>

---------

Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com>
2026-10-18 16:15:39 -06:00
Osvaldo DuranandClaude Opus 5.5 c257793c2c Merge upstream main dab31491 into pr/attachments
On top of the merge with 932bf9c6; no conflicts. ATTRIBUTION.toml is upstream's with every sha256 recomputed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 17:27:27 -04:00
Perchenko Anton 6fc17441ac fix(forms): edit button labels in field properties (#3064)
* M6: edit push-button labels in field properties (#2892)

* M6: keep roadmap status blockquotes valid

* M6: keep button-caption roadmap notes minimal
2026-10-18 17:04:49 -04:00
Osvaldo DuranandClaude Opus 5.5 f24a26b951 Merge upstream main 932bf9c6 into pr/attachments
Conflicts: ATTRIBUTION.toml, crates/organize/src/tests.rs (code resolved by hand: crates/organize/src/tests.rs). Catalogs keep upstream's rows, then this branch's rows upstream lacks; ATTRIBUTION.toml is upstream's with every sha256 recomputed; progress lines keep both sides, upstream's first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 14:59:30 -04:00
Marco Arnulfo 9e0937c3f7 M12: the Visual filter only hides shading, since visual differences are never listed: say so 2026-10-18 20:38:18 +02:00
jonathanwxh-cell 9b0aeb0f69 M11: integrate main b0e5c6eb into PR #3227 and fix version parser lifetime 2026-10-19 02:35:26 +08:00
PerchAnton 031532b8a5 M4: bound named-destination pruning during page deletion (#3309) 2026-10-18 21:01:43 +03:00
Marco Arnulfo d7f8ba8b57 fix(forms): Tab and Space reach check boxes and radio buttons, and a click focuses them (fixes #2223) 2026-10-18 19:55:32 +02:00
Marco Arnulfo 1a12b0094d Preferences: always use my default zoom and page layout (fixes #1618) 2026-10-18 19:34:04 +02:00
Marco Arnulfo a4cdbb6235 XFA: decode BMP and TIFF pictures (fixes #1644)
Pictures in templates and data that are BMP or TIFF were left out with a
warning. They are now recognised by their signature, sized from their
headers, and decoded through the same bounded reader as GIF (first page
of a TIFF). A BMP needs a valid info-header size after "BM", so text
starting with those two letters is still not taken for one.

A BMP or TIFF chosen for an XFA image field is kept in the data as
image/bmp or image/tiff, since the layout can now show it.
2026-10-18 19:21:49 +02:00
alehel 9b6e74928f Merge remote-tracking branch 'origin/main' into fix/background-hidden-by-page-backdrop
# Conflicts:
#	ROADMAP.md
2026-10-18 19:17:34 +02:00
Mawfyy 932bf9c6bf M4: Ctrl-drag copies pages in the Organize grid (#2997) (#3092)
* M4: Ctrl-drag copies pages in the Organize grid (#2997)

Dragging thumbnails in the Organize page grid with Ctrl held (Option on
macOS) drops copies at the gap instead of moving the pages: a "+" badge
by the pointer, the copies land at the gap selected, and one undo step
takes them out. The insertion point joins the engine edit
(Edit::DuplicatePages { at }) so the copy is one undo step rather than a
duplicate plus a move.

page_duplicate takes a 1-based "at" (the first copy becomes page "at"),
so agents can drive the same thing, and the UI control channel's
ui.drag modifiers now reach the input state -- which gestures that read
it (this copy-drag, and Alt-drag column select) need.

Closes #2997.

* fix(ui): take the grid's copy modifier from the runtime OS (#3092 review)

Option-drag in the Organize grid moved the pages instead of copying them in a Mac
browser: `cfg!(target_os = "macos")` is false in the wasm build, and eframe sets the
context's OS from the browser. `copy_modifier` now takes the context and asks
`commands::mac_shortcuts`, as the shortcut labels do.

The drag helpers in `tests/editing.rs` and `tests/control.rs` picked the modifier the
same compile-time way, so they would have sent Ctrl on a Mac host; both read the
context's OS now. The new regression test
`option_copies_and_ctrl_moves_when_the_context_reports_macos` drives a Mac context —
Ctrl moves, Option copies — and fails without this change.
2026-10-18 11:13:22 -06:00
Marco Arnulfo 9f536c9efd M12: Compare panel filters text changes and visual differences (gap 21) 2026-10-18 18:59:13 +02:00
Marco Arnulfo fcdf2a2146 Layers panel: Reset to Initial Visibility
Layer options in the Layers panel header resets every layer to the state the
file's default configuration (/OCProperties /D) gives it, as Acrobat does.
Visibility is view state, so the reset doesn't mark the document changed and
doesn't enter Undo. doc_info now reports each layer's initial state.
2026-10-18 18:56:40 +02:00
Marco Arnulfo 3468c8543f fix(print): disable Print on documents whose security forbids printing (part of #2669) 2026-10-18 18:56:08 +02:00
enes yıldızandClaude Opus 5.5 882b5a33bc M1: merge upstream main into claude/fix/2670-cli-owner-password
Merges #2813 (dynamic-XFA layout in the CLI) into the owner-password branch. In
info, text and render the engine Session and the cos document keep the typed
password, while anything handed to `inspect` or `PageRenderer` gets the render
password (the user password recovered from an R2-R4 owner password), including
the dynamic-XFA detection in render and the original-bytes check in text.

Checked: cargo fmt --check; clippy -p pdfcraft-cli -p pdfcraft-engine --all-targets
-D warnings; cargo test -p pdfcraft-cli (75 passed) and -p pdfcraft-engine (283 lib
+ integration passed); cargo xtask layers, assets, parity; a throwaway RC4-40,
RC4-128 and AES-128 dynamic-XFA check with the owner and user passwords through
info, text and render (not committed).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 19:44:21 +03:00
PerchAnton 12210a350d M12: retain product notes while integrating current main 2026-10-18 19:42:01 +03:00
PerchAnton b7b4ab0c8d M12: retain product notes while integrating current main 2026-10-18 19:39:17 +03:00
PerchAnton c3df50e8dd M12: retain product notes while integrating current main 2026-10-18 19:36:34 +03:00
PerchAnton d39de3d31c M12: retain product notes while integrating current main 2026-10-18 19:33:52 +03:00
PerchAnton 28e6d4e773 M7: retain product notes while integrating current main 2026-10-18 19:18:04 +03:00
PerchAnton 613503f5a0 M7: preserve rotation and index regressions on current main 2026-10-18 19:10:36 +03:00
PerchAnton e75551ce62 M1: reject partial resource-fork copies and integrate current main 2026-10-18 19:03:07 +03:00
Lucas Dias d6f872b665 M12: avoid white flashes while reading pages render 2026-10-18 12:49:00 -03:00
alehel dc27841010 Merge remote-tracking branch 'origin/main' into fix/background-hidden-by-page-backdrop
# Conflicts:
#	ROADMAP.md
#	crates/ui-egui/tests/ui_group/marks.rs
2026-10-18 17:34:42 +02:00
PerchAnton 778c561d76 M12: retain product notes while integrating current main 2026-10-18 18:14:25 +03:00
PerchAnton 8a786ab2d9 M12: retain product notes while integrating current main 2026-10-18 18:11:02 +03:00
PerchAnton 0910b8314a M12: retain product notes while integrating current main 2026-10-18 18:07:15 +03:00
mtlcl410andClaude Fable 5.1 7ec435eb4d fix(print): Properties… reads CUPS driver options off the GUI thread, with a deadline for lpoptions (#1818)
The Print dialog's Properties… ran lpoptions on the GUI thread with no
deadline, so a CUPS that stopped answering froze the window. The read
now runs on its own thread (the panel says so meanwhile, and a read
that dies offers nothing rather than waiting), and lpoptions gets ten
seconds through spool::output_within, which kills and reaps a command
at its deadline; the PPD's own defaults then stand. One UI string in
the 21 catalogues.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz
2026-10-18 23:03:31 +08:00
PerchAnton 4f4f589365 M12: retain product notes while integrating current main 2026-10-18 18:02:45 +03:00
aiongg 40d7b0bc47 Merge upstream main a12fe8f41 into next 2026-10-18 14:56:01 +00:00
PerchAnton 42a31db308 M7: retain product notes while integrating current main 2026-10-18 17:51:48 +03:00
aiongg eedf250b4c Merge upstream main ecffce69e into next
crates/cos/src/document.rs: both new accessors, header_offset (#2525) and reconstructed (#2029).
parity/acrobat-features.toml: the malformed-xref entry has both sides' evidence and notes (#2029 full save of a repaired file, #2717 table numbered from 1).
2026-10-18 14:50:20 +00:00
a12fe8f411 M4: custom document properties through the engine and the tools (#2076)
* M4: custom document properties through the engine and the tools (#organize.custom-properties)

/Info entries beyond the ones the spec names are custom properties:
organize lists them (custom_info) and set_info accepts any such name
after Acrobat's checks (no standard name, no empty name, no spaces,
delimiters, / or #, at most 127 bytes); inspection lists them too
(DocInfo::custom); doc_info reports them under custom and doc_set_info
sets or clears them. The Custom tab in Document Properties and the XMP
mirror stay planned.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz

* M4: custom document properties list the same before and after an edit

Review follow-up. The open-time reader (render/inspect.rs) now uses the
engine's rule (pdfcraft_organize::custom_info, trimmed, empty values
dropped): text strings only, NUL/whitespace trimmed, empty values left out,
and the 256 cap counting listed entries. Before, it also listed name
values (`/Dept /RnD`) and capped before filtering, so the list could change
after the first unrelated edit. An automation test opens a file with a name
value, blank, NUL-padded, empty and numeric entries and checks doc_info's
custom list is the same before and after setting the Title.

Drops the ROADMAP.md log line, which conflicted with main.

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

* M4: custom properties drop NUL/whitespace padding in one pass, before the cap

Review follow-up. custom_info now trims NULs and whitespace in any mix
(" \0Lab\0 " is "Lab"), leaves out values that are only padding, and does
both before taking 256, so blank entries can't crowd real ones out. It is
the one rule: the engine uses it as it is, and the open-time reader trims
the same way. Tests: 300 blank entries before a real one, and mixed
padding, in organize and through doc_info.

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

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 10:49:30 -04:00
mtlcl410andClaude Opus 5.5 ecffce69ee fix(engine): Save writes a repaired file in full even without edits (#1937) (#2029)
* fix(engine): Save writes a repaired file in full even without edits (#1937)

A damaged file is repaired on open (its cross-reference index rebuilt from
object headers, as Document Properties reports), but Save wrote it back as it
was: `Session::save_bytes` returned the bytes as opened whenever nothing was
edited, and a repair is not an edit. The "repaired" file on disk was still the
damaged one.

`save_bytes` now writes a reconstructed document in full even with no edits.
`Document::reconstructed()` in cos names the condition (no revision chain:
rebuilt, or built from scratch), and `write_incremental` uses it too, so the
writer and the engine share one definition.

Tests: `engine::tests::a_repaired_file_is_rewritten_by_save_even_without_edits`
(table offsets shifted; no table at all) and
`automation::saving_a_repaired_file_puts_the_repair_on_disk` (doc_open,
doc_info, doc_save over the same path, reopen). Both fail with the condition
removed: the saved bytes equal the damaged file. parity: core.repair-broken-files
cites them and notes that a repair still does not count as an unsaved change.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz

* fix(engine): a signed repaired file keeps its bytes on Save without edits (#1937)

Review follow-up: writing a reconstructed file in full on Save puts the
repair on disk, but for a signed file it would also invalidate its
signatures without warning. Save now skips the early return only when the
document is reconstructed and not signed. A regression test signs a
document, appends a `startxref` that points nowhere (the signed bytes stay
intact, the cross-reference data must be rebuilt) and checks that Save
without edits returns those bytes.

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

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-18 10:47:28 -04:00
PerchAnton 57c5dde167 M7: preserve rotation and index regressions on current main 2026-10-18 17:39:44 +03:00
PerchAnton e45a1db89f M1: reject partial resource-fork copies and integrate current main 2026-10-18 17:30:26 +03:00
aiongg b6b02a1b27 Merge upstream main 1952a8880 into next
ROADMAP.md, docs/roadmap.md: union of both sides' lines, each once.
parity/acrobat-features.toml: the XFA entry has both sides' evidence and notes (#2604 page areas, #2813 CLI layout).
2026-10-18 14:22:30 +00:00
alehel 911147126c Merge remote-tracking branch 'origin/main' into fix/background-hidden-by-page-backdrop
# Conflicts:
#	ATTRIBUTION.toml
2026-10-18 16:05:19 +02:00
jonathanwxh-cell 3c94700447 M11: document partial PDF version compatibility (#3227) 2026-10-18 21:54:58 +08:00
1952a88801 fix(cli): use laid-out pages for dynamic XFA forms (#2813)
Fixes #1645. For a dynamic XFA form, `info` reported the placeholder
page and field counts, and `text` and `render` read the placeholder
pages, while the app and the automation tools lay the template out.

The CLI now opens dynamic XFA forms through the engine session and uses
its laid-out document for page and field metadata, text and pixels.
`info` keeps the input's file size and also reports the original counts
as `pdf_pages` and `acroform_fields`; `text` checks the copy permission
before extracting. The input file is never written.

Checks run (rustc 1.99.0): cargo fmt --check; cargo clippy -p
pdfcraft-cli --all-targets -- -D warnings; cargo test -p pdfcraft-cli;
cargo xtask layers; cargo xtask assets.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 09:54:00 -04:00
6525140955 M3: type an exact zoom into the rail's zoom field (#1755)
* M3: type an exact zoom into the rail's zoom field

The rail's zoom percentage was a read-only label. It is now a text field:
Enter applies a typed percentage (150, 150%, 62.5 %), Escape or unparsable
input keeps the current zoom. The control channel's zoom option uses the
same parser.

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

* M3: document parse_zoom_percent

* i18n: Vietnamese for the zoom field's tooltip

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 09:53:24 -04:00
Marco ArnulfoandBrandon Thomas b68b3c1119 M3: the Pages panel follows the current page (#2785)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 09:52:40 -04:00
2c4989413f M7: the Edit text caret is as tall as the row it is on (#2462)
In a region that mixes sizes (a 24 pt title over 12 pt lines), the
inline editor's caret on a small row was as tall as the region's first
size and reached into the row below. egui draws the caret at least one
row of the TextEdit's font tall, and that font had the paragraph's first
size. Each row already carries its source row's height, so the
TextEdit's font is now half the region's smallest size and only sets
that floor.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 09:51:52 -04:00
mtlcl410andClaude Opus 5.5 2bd6d1357d M5: flattening comments leaves 3D, multimedia and print-production annotations (#3087) (#3089)
doc_flatten with comments chose every non-widget annotation except Link
and Popup, so a comments-only flatten baked in and deleted 3D, Screen,
Movie, RichMedia, PrinterMark, TrapNet and Watermark annotations with
their data (a 3D annotation's U3D model and default view). The comments
branch now uses pdfcraft_annot::is_comment_subtype, the classifier the
comment list uses; widgets follow `fields` only.


Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 09:48:26 -04:00