Commit Graph
2978 Commits
Author SHA1 Message Date
.CooCoo 2ac1df2f1f M4: Document Properties has a Custom tab for custom properties (#4387)
* M4: Document Properties has a Custom tab for custom properties

Document Properties has a new Custom tab between Fonts and Advanced. It
lists the document's custom properties, and Name and Value fields with
Add, Update and Delete edit the list. Clicking a listed property fills
the fields with it. OK writes the changes through SetInfo in the
existing "Change document properties" step, so one undo reverts them
with the other tabs' changes.

Add is off for an empty value, a name already listed, a name that
check_custom_key refuses (its message is the button's tooltip), and a
name the file already uses for an entry the list leaves out (not text,
only padding, or past the 256 listed). A property already in the file
under a refused name or a name that is not UTF-8 is listed, and Add,
Update and Delete stay off for it, so OK cannot fail on it or write a
different key.

Clearing an /Info entry now removes it when /Info is a dictionary
written directly in the trailer. set_info_entry returned without a
change there, so a delete in the Custom tab, a cleared Description field
and a doc_set_info clear left the entry in the file. It now writes a
copy without the entry as a new indirect /Info.

The engine re-exports check_custom_key and adds Document::has_info
(organize::has_info). set_option("dialog", "custom") opens the tab.

* Contributors: add dotCooCoo (Robert Lee)

* M4: Add in the Custom tab stops at the 256 properties the tab lists

Document Properties > Custom lists at most 256 properties, so a property
added past that was saved but left out of the list when the dialog opened
again. Add is now off once the tab's list or the file's own list holds 256;
a new name goes after the file's entries, so a file with more than 256 keeps
Add off after a Delete as well.
2026-10-24 10:30:25 -04:00
mtlcl410andClaude Opus 5.5 fc91ab9250 M3: a document opens at its /OpenAction destination, position and named destinations included (ISO 32000-2 Table 149, 12.3.2.4) (#4376)
- render: DocInfo::open_dest resolves /OpenAction (an explicit destination,
  a /GoTo action's /D, or a name or string through /Names /Dests or the
  catalog /Dests) with the existing bounded dest() resolver.
- ui-egui: apply_initial_view goes there with DocView::go_to_dest, so the
  /XYZ point lands at the window's top-left and /FitH top at its top edge.
  With "Always use my default zoom and page layout", only the page.
- organize, ui-egui: /ViewerPreferences /NonFullScreenPageMode (Table 147)
  is read for /PageMode /FullScreen documents and names the panel shown
  behind the full-screen prompt; such a document no longer gets the outline
  panel only because it has an outline.
- organize: set_initial_view keeps an opening action whose page and
  magnification are unchanged, instead of dropping its position or deleting
  a named go-to.
- automation: doc_info reports open_destination.


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

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 10:30:21 -04:00
mtlcl410andClaude Opus 5.5 4f436d3dd4 M5: line comments draw their leader lines and caption (ISO 32000-2 Table 178) (#4354)
A Line annotation without an appearance was drawn along /L with its
endings there, ignoring /LL, /LLE, /LLO, /Cap, /CP and /CO. With /LL,
/L gives the ends of the leader lines, not of the line itself.

- The line sits |LL| + LLO from /L, on the left of travel for a
  positive /LL; leader lines run from LLO off /L to LLE past the line.
- /LE endings are drawn at the line itself.
- /Cap true draws /Contents (or the plain text of /RC) in black
  Helvetica 10, turned with the line: Inline breaks the stroke around
  it, Top sets it above, /CO shifts it (with a tick when moved off).
- PdfCraft measurements keep /PCMeasureValue as their caption.
- undrawable_text reports caption text the standard font can't draw.
- Non-finite, huge and negative values, and a zero-length /L, are
  handled leniently; captions are cut to 256 characters.


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

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 10:30:16 -04:00
Eric Kaden 96cf936b31 M12: XFA check boxes sit where their margins, caption and alignment put them (#4300)
* M12: XFA check boxes sit where their margins, caption and alignment put them

* M12: a check box's automatic caption room and auto height follow the box as drawn

* M12: a caption reserve of zero sizes the caption to its content, as no reserve does
2026-10-24 10:30:11 -04:00
Gabriel Luís da Silva be0ec70756 fix(automation): roots-only mode refuses other shares and devices by name (#4289)
With only --automation-read-root / --automation-write-root set, a path
went straight to std::fs::canonicalize, so a UNC, WebDAV or device path
(`\host\share\x.pdf`, `\.\pipe\x`) was resolved, contacting the host,
before it was refused. `--root` mode already refuses those by name
(`foreign_share`).

`foreign_share` moves into file_access, and `AutomationRoots::check_path`
applies it to the path made absolute (by name, nothing read) before
following links, with the same refusal as any other path outside the
root. A root on a share still accepts that share. `resolve` is split
into `absolute` (empty path, device names, made absolute) and `resolve`
(links followed), so `out\NUL` keeps its own refusal.

Part of #4003 (the first of its three points).
2026-10-24 10:30:06 -04:00
mtlcl410andClaude Opus 5.5 a08ec799f5 M2: tiling pattern cells sit at their XStep/YStep multiples at every scale (ISO 32000-2 8.7.3.1) (#4421)
The cell pixmap was round(scale x step) pixels and repeated, but the cell
was drawn, and the paint transform mapped back, at the unrounded scale.
So the pixmap repeated a fraction of a pixel too far at every step (31 px
for a 30.56 px step at 110 dpi), and cells drifted further from their
place with every step from the pattern's origin.

Vendored hayro patch (25), `tiling_cell_pixels`: the cell is drawn at
round(scale x step) / step, so one step is exactly the pixmap's side, and
the paint transform uses that same scale. The side stays within 1 and the
existing 3000 px cap; a non-finite product keeps the scale and a bounded
side.

Tests: crates/render/tests/it/tiling_cell_placement.rs (fill, turned and
scaled matrix, stroke, all at 110 dpi far from the origin; the helper's
bounds).


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

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 10:30:02 -04:00
Daniele LombardiandClaude Opus 5.5 4047e9aaa5 fix(ui): seven tools take the page zoom from the side the page's width is on (#4425)
With the view turned 90 or 270 degrees, the page's screen rectangle has
its sides swapped, so xf.rect.width() / xf.pw was off by the page's
height over width: Fill & Sign, form fields and Add text drew typed text
at the wrong size, and Measure snapping, Prepare form, the calculation
order and field table overlays were sized wrong too. They now use
PageXform::zoom (from #3749), which reads the side the width is on.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 10:29:58 -04:00
FredAppsandFredApps 47d2a8f16e refactor(ui): separate field-table divider input from painting (#4419)
Co-authored-by: FredApps <FredApps@users.noreply.github.com>
2026-10-24 10:29:52 -04:00
Dylan M. TaylorandClaude Sonnet 5.5 39d69c3165 refactor(engine): extract quad_score and page_has_form_xobject (Sonar S3776) (#4408)
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 10:29:47 -04:00
Dylan M. TaylorandClaude Sonnet 5.5 486949424c refactor(a11y): extract text_spans and xobject_bbox helpers (Sonar S3776) (#4407)
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 10:29:43 -04:00
Dylan M. TaylorandClaude Sonnet 5.5 ff267d6883 refactor(xtask): split parity evidence and layers dependency checks (Sonar S3776) (#4406)
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 10:29:38 -04:00
.CooCoo 02b6fcc5ef fix(optimize): a GoToR or GoToE /D no longer keeps a local named destination (#4445)
Clean Up removes named destinations that nothing in the document refers
to. referenced_names counted the /D of GoTo, GoToR and GoToE actions
alike. The /D of a GoToR or GoToE action names a destination in another
document, so a local destination with the same name was kept although
nothing in the document used it.

Only a GoTo's /D now counts as a use. A /Dest key and a GoTo's /D are
read as before.

Test: links with a GoTo, a GoToR and a GoToE action name three
destinations; optimize() keeps the one the GoTo uses and removes the
other two.
2026-10-24 10:29:33 -04:00
oracola91 bc4f8e2602 Redaction keeps images still drawn through a form without /Resources (#4413)
content_draws tells whether some content draws an XObject, directly or
through a form that has no /Resources of its own and so draws through
its caller's. Since #4356 the recursion passed the caller's content
again instead of the nested form's decoded data, so a name drawn only
inside such a form was never found.

Both callers then dropped the entry: unlink_doomed for page-tree
resources (Apply Redactions and the content pass of Remove Hidden
Information) and prune_doomed_xobjects for surviving forms. An image
removed under a mark but still shown elsewhere through such a form went
missing from there as well.

The recursion reads the nested form's data again, as it did before
#4356. Two tests cover the page-tree case and the surviving-form case.
Both fail without the fix.
2026-10-24 10:29:28 -04:00
Roopesh O R 4e9b214e4a Fixed broken link to nFPM installation site (#4372)
* Fixed nfpm installation site

* fix bracket
2026-10-24 10:29:23 -04:00
aiongg fc1372a64c fix(render): vendor hayro-postscript so a run of << in a CMap can't overflow the stack (#4363)
hayro-cmap reads CMap streams with hayro-postscript's token scanner,
whose object::read skipped each `<<` and `>>` by calling itself again.
A CMap holding a long run of `<` or `>` used one stack frame per pair,
overflowed the stack and aborted the process.

Vendor hayro-postscript 0.1.0 with read() looping over the delimiters
instead (from storytold/craft-libs#263), patched in beside hayro-cmap.
Four object::tests cover long `<<` and `>>` runs and the skipped
delimiters, plain and nested.
2026-10-24 09:38:10 -04:00
aiongg b6b0bbab08 fix(forms): a multiline field rejects a glyph wider than the field (#4447)
TextBox::fits checked only the height of a wrapped multi-line value.
Long words break by character, so a single character wider than the
box still overflows it, and the appearance reports Overflow::Wide for
a value fits had accepted. The multi-line branch now also requires
every wrapped line to fit the width.
2026-10-24 09:37:35 -04:00
aiongg b75cbd92c5 Merge pull request #4394 from aiongg/r3-batch-c
Integration batch 5: 9 contributor PRs (OCR, attachments, documents, selection), after #4391
2026-10-24 08:40:40 -04:00
aiongg 885ae3faf1 Merge pull request #4391 from aiongg/r3-batch-b
Integration batch 4: 26 contributor PRs (comments, viewer, pages, printing), after #4390
2026-10-24 08:39:00 -04:00
aiongg 0b51b20492 Merge pull request #4390 from aiongg/r3-batch-a
Integration batch 3: 47 contributor PRs (editing, forms, XFA, rendering)
2026-10-24 08:37:51 -04:00
aiongg 2ae1e915c9 fix(ui): comment composer visibility uses the shown rectangle 2026-10-24 12:13:22 +00:00
Dylan M. TaylorandClaude Sonnet 5.5 c894928e6f fix(demo): showcase font-display, distinct link text, SVG accessible names (Sonar) (#4402)
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 04:37:33 -04:00
aiongg afa14c3b98 Merge integration batch A's review fixes 2026-10-24 08:26:10 +00:00
aiongg f9a179fee0 Merge integration batch B's review fixes 2026-10-24 08:26:10 +00:00
aiongg 70404ac310 Integration: format the review-fix tests (#4339) 2026-10-24 08:24:09 +00:00
aiongg 9595f5940c Integration: a script-opened panel reveals a background Inspector tab (#3580)
ShowPanel now queues the same Inspector reveal a user's panel choice does.
2026-10-24 08:24:01 +00:00
aiongg 82eedb6607 Integration: a retained-version optimize reports the later of header and catalog version (#3227)
Object streams raise the header to 1.5 over a lower catalog /Version; pdf_version now reports the version viewers read.
2026-10-24 08:21:14 +00:00
aiongg 29889fc1e0 Integration: list the attachment edit labels for translation (#1960)
"Attach {name}" and "Delete attachment {key}" were missing from EDIT_LABELS, so the translation-gap report left them out.
2026-10-24 08:20:44 +00:00
aiongg 1fb1877923 Integration: attachment_add reads its file through the size-capped reader (#1960)
attachment_add used an unbounded std::fs::read; it now uses read_input like the other file-reading tools, and the oversized-input test covers it.
2026-10-24 08:20:39 +00:00
aiongg be826a3bcd Integration: a short multi-line field accepts the line it draws (#4339)
The fit check required the padded height for every line; it now uses the bound the appearance applies, so a 16 pt field at 12 pt takes one line.
2026-10-24 08:17:01 +00:00
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 b04257d5eb Integration: a typed Password-field value stays in the open document after Save (#3943)
Recording a save reopens the saved file, which carries no Password values; they are put back in memory only, so the next save still omits them.
2026-10-24 08:15:01 +00:00
aiongg 8021aee1f8 Integration: the edit composer stays visible while part of its comment is on screen (#4095)
Editing a large comment whose top-right corner was scrolled away opened a composer that was hidden and could not be cancelled. The card now stays, clamped into the document, while any part of the comment shows.
2026-10-24 08:14:45 +00:00
aiongg 2208dc16c8 Integration: cargo fmt 2026-10-24 07:32:52 +00:00
aiongg 7685882aa1 Merge integration batch C (track r3-t07) 2026-10-24 07:25:53 +00:00
aiongg 8ce5a3ec96 Merge integration batch A at #2648's updated head 2026-10-24 07:24:24 +00:00
aiongg 315454d3a9 Merge PR #2648 at its updated head
# Conflicts:
#	crates/engine/src/js.rs
2026-10-24 07:21:13 +00:00
aiongg 35f3fe027e Integration: #3694 a press beneath a menu or dialog does not end Select All
The reset uses pressed_page (unobstructed, pointer over the page) instead of the raw press origin; the test presses with a dialog open.
2026-10-24 07:20:42 +00:00
aiongg 2e561bb635 Merge integration batch B (tracks r3-t05, r3-t06) 2026-10-24 07:12:16 +00:00
aiongg 95ec6348c3 Merge upstream main into integration batch A
# Conflicts:
#	crates/ui-egui/tests/it/control.rs
#	crates/ui-egui/tests/it/forms.rs
2026-10-24 07:12:10 +00:00
aiongg 7733b619cf Integration: #3670's fan-out test allows for a loaded machine 2026-10-24 07:11:16 +00:00
aiongg a9fe3d4e7f Integration: drop the doc comment of the removed visit cap (#3670 × main) 2026-10-24 07:11:16 +00:00
aiongg 2a91f1d717 Integration: the page's decode budget owns the form count in redaction (#3670 × main)
#3670 raised the form depth limit to 50 and added its own 50,000-visit cap. Main's
per-page DecodeBudget (e2a677164) has the same 50,000-form limit, and the visit cap
fired first, so Apply removed the forms instead of refusing the page as main does.
The visit cap goes; the fan-out test expects the refusal, and the depth-limit
sanitization test builds its chain from MAX_DEPTH.
2026-10-24 07:11:16 +00:00
aiongg e05dc237bb Merge upstream main into the r3 batch
# Conflicts:
#	crates/ui-egui/tests/it/forms.rs
2026-10-24 07:11:15 +00:00
aiongg 2ffcd0f1d1 Merge PR #3694: Select All takes the whole document's text while scrolling continuously (fixes #2639) 2026-10-24 07:10:11 +00:00
aiongg deffc376cf Integration: #2588 keep XMP-only document information across full refreshes
Session::refresh_with_indexes fills title, author and the other fields from XMP as build_document does; the test applies an edit and an undo and checks they stay.
2026-10-24 07:10:11 +00:00
aiongg 91b6f7f172 Integration: #3670's fan-out test allows for a loaded machine 2026-10-24 07:06:18 +00:00
aiongg b232ed217c Merge PR #2588: M3: Document Properties shows a title and author stated only in XMP (#2373) 2026-10-24 07:00:29 +00:00
aiongg cededfaccb Integration: #1960 put the attachment_action doc line back above attachment_action 2026-10-24 07:00:29 +00:00
aiongg f053da3d93 Merge PR #1960: Attachments: attach a file and delete one (panel, edit, tools); duplicate names numbered as text
i18n ca, fi, hi, id, ko, ro, sq .tsv: kept both sides' rows (no duplicate keys).
2026-10-24 07:00:24 +00:00
aiongg 464dbd49e0 Integration: #3765 name the case-only comparison in the doc comments (NFC/NFD not compared) 2026-10-24 07:00:10 +00:00