Commit Graph
4058 Commits
Author SHA1 Message Date
FredApps 66a7667aca Merge current main into idle autosave branch
Preserve the idle repaint and second-edit recovery regression while refreshing already-merged upstream work. Validated exact tree with full local CI and native Linux idle recovery.
2026-10-16 19:50:09 +02:00
Guillem Hermida 743b3861d0 fix(render): draw device colour in the resources' /DefaultGray, /DefaultRGB and /DefaultCMYK (vendored hayro-interpret patch 38)
A resource dictionary's DefaultGray, DefaultRGB and DefaultCMYK colour
spaces replace the device space content selects (ISO 32000-2 §8.6.5.6).
hayro ignored them: g/G, rg/RG and k/K set the device space directly,
cs/CS resolved the device names before looking at the resources, and
images took their /ColorSpace as written. Pages that calibrate device
colour this way, common in PDF/A, came out in the wrong colours.

The interpreter now looks the defaults up once per content window
(DefaultColorSpaces), in the resources and those they inherit, so a form
XObject without its own draws in its page's. They replace DeviceGray,
DeviceRGB and DeviceCMYK selected by the colour operators, by cs/CS (by
name or through a /ColorSpace resource that is a device space), and as
the /ColorSpace of image XObjects and inline images. A default that is a
Lab, Indexed, Pattern or device space, has another number of components
or is not a colour space is ignored, and device colour is drawn as
before. Device spaces nested in other spaces, shading dictionaries,
masks and transparency group spaces are unchanged. The decoded-image
cache keys a decode by the default it was drawn in, since one image can
be drawn with and without one.

Part of #1201.
2026-10-16 19:41:22 +02:00
Marco Arnulfo b2150f3ffd Forms: measure a field's own simple font, not Helvetica, when laying out its text (fixes #2894) 2026-10-16 19:37:00 +02:00
mtlcl410andClaude Opus 5.5 4a35a1cb23 M9: rewriting a certified form's XFA data is a form fill (#2759)
The IRCC IMM forms are certified (DocMDP P=2) and then saved once more
with Reader Extensions: a later revision adds the UR3 usage-rights
signature and rewrites the XFA `datasets` packet. The diff classified any
rewritten stream that wasn't page content or the catalog's XMP as "other
changes", so these untouched forms validated as invalid.

A stream the signed revision's /AcroForm /XFA array names `datasets` or
`form` (the form's data and state) is now a form fill when rewritten,
permitted at P=2 and P=3 and refused at P=1 as before. The roles come from
the signed revision, so a later revision that names the template
"datasets" doesn't make rewriting it a form fill.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz
2026-10-17 01:21:28 +08:00
Guillem Hermida f4ee74db05 fix(comments): the note editor takes the keyboard once, so V and H pick tools again
After a highlight, its note editor in the Comments panel kept the
keyboard, so V and H were typed into the note (#2669, item 2).

- The editor asked for the keyboard on every frame when no other widget
  had it, so it took it back after every click elsewhere. It now takes
  it once, when it opens (CommentView::open_editor, EditorFocus::Take).
- Adding another comment left the editor open, and drawing is a drag,
  which egui doesn't treat as a click elsewhere. An empty editor on
  another comment now closes when a comment is added; one with text
  stays open with it but gives the keyboard back (EditorFocus::Release).

Part of #2669.
2026-10-16 18:59:04 +02:00
Guillem Hermida 437b691eb7 fix(ui): the Read mode command leaves Edit as the Edit tab does
#2241 made leaving the Edit tab put Edit text & images down and apply a
paragraph still open in the editor, but only in select_mode, which only
the mode bar reaches. The Read mode command (View > Read mode, Ctrl+H,
the command search) went through switch_mode's other branch, which only
set the mode: Read mode then kept Edit text & images on, every paragraph
boxed, and an open paragraph editor floating over the page with its edit
not applied.

enter_mode now sets the workspace together with its tool, and both
routes go through it, so they can't drift apart again. The command still
leaves the panels as they were.

Test: editing.rs::the_read_mode_command_applies_an_open_paragraph_and_puts_edit_text_down
2026-10-16 18:25:57 +02:00
Harrison BoothandClaude Sonnet 5.5 f976adeb17 M3: the "Save changes?" prompt opens on Save and moves between buttons by keyboard
Save is chosen when the prompt opens, so Enter saves as before. The arrow keys
and Tab / Shift+Tab move the choice between Don't save, Cancel and Save, shown
with a focus ring; Enter or Space press the chosen button, Escape cancels.
Before, Enter always saved, even with another button reached by Tab.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-16 11:20:11 -05:00
Combiler01 9e78afa9c2 merge: reconcile upstream/main with 8-handle image interaction and arrange fixes 2026-10-16 21:44:43 +05:30
Combiler01 035183777a fix:implement 8 point non destructive crop, image resize and Arrange extraction bugs 2026-10-16 21:24:49 +05:30
Guillem Hermida fbd9911d76 fix(forms): renaming a nested field checks the full name it would take
Renaming a field changes only its own /T, so MASTER.a renamed to b
becomes MASTER.b. set_props compared the bare new partial name with the
other fields' fully qualified names: renaming MASTER.a to b succeeded
while MASTER.b existed, leaving two fields with one fully qualified
name, which are one field with a shared value (ISO 32000-2 §12.7.4.2);
and renaming MASTER.a to c was refused because of an unrelated
top-level field c.

The check now compares the new full name, leaving the field itself out
so a kid keeping its own partial name still succeeds, and the error
names that full name. Top-level renames are checked as before.
2026-10-16 17:48:47 +02:00
Tiago KielandClaude Opus 5.5 2c4645de41 fix(cos): check object-stream member numbers and offsets (#1815)
Object-stream members were indexed with unchecked casts: `/First` and each
offset went through `as usize` and an unchecked addition, which truncate or
wrap on 32-bit targets such as the wasm32 build, and the member number went
through `as u32` on every target, so a member numbered 2^32 + 3 was read as
object 3. A negative offset was clamped to zero and read the stream's first
member instead.

Each member is now converted and added with checks, and kept as an unusable
slot (preserving positions, which cross-reference entries refer to) when its
number is not an object number or its start falls outside the decoded data.
Looking such a member up is a MissingObject error, as for any other absent
object.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 11:43:25 -04:00
Guillem Hermida 359a3f2f09 M11: Optimize keeps a JPEG's colour transform (#1201)
Optimize decoded DCT images with the generic JPEG decoder, which converts
three components from YCbCr to RGB whenever the JPEG itself doesn't say
otherwise, and then dropped /DecodeParms. An RGB JPEG stored untransformed
(/ColorTransform 0 and no Adobe marker) therefore came out in other colours
when recompressed, resampled or merged from strips.

The samples are now read with the colour transform ISO 32000-2 §7.4.8
gives them: an Adobe APP14 marker's flag, else /ColorTransform (default 1).
Untransformed samples are taken as stored, and the result is written as a
plain YCbCr JPEG (or Flate), which needs no /DecodeParms. When the marker
and /ColorTransform disagree, a value is out of range, the parameters are
not paired with the filter as §7.4 pairs them, or the decoder reads the
components otherwise (named R, G and B), the image is left as it is.

The tests draw each image with PdfCraft's renderer before and after
Optimize: RGB JPEGs with and without an Adobe marker under each
/ColorTransform, CMYK JPEGs (still left alone) and JPEG strips merged into
one picture.

Part of #1201.
2026-10-16 17:28:19 +02:00
Guillem Hermida 282ce56675 M12: the page side of a measuring scale takes a unit, so 1:50 is 1 mm = 50 mm (#2752)
The Measure panel's drawing scale had its page side fixed in PDF points, so
"1 = 50 mm" was stored as 1 pt = 50 mm and every length came out
72 / 25.4 = 2.835 times too big (a 1:50 plan needed 50 x 25.4 / 72 = 17.64).

The page side now carries a unit (pt, in, mm, cm). It defaults to the
real-world unit, and to the display unit when that is not one of the four.
Scale::ratio converts it to points before building the /X, /D and /A number
formats (ISO 32000-2 12.9) and writes /R as entered ("1 mm = 50 mm").
measure_scale takes the same ratio through page_distance and page_unit.
Scales read from files, Scale::calibrate and units_per_point are unchanged.

Fixes #2752
2026-10-16 17:25:26 +02:00
FredApps 8b5ecf8b04 fix #2444: cancel typed font-size edits on Escape and refresh main
Preserve already-merged upstream work and add the focus-loss/Escape regression. Exact candidate tree qualified with workspace tests, 31 WASM checks and a separate successful dependency audit.
2026-10-16 16:54:31 +02:00
mtlcl410andClaude Opus 5.5 aea1d3d127 M1: put valid_xref_range's doc comment back, and no trailing spaces in the tests (#2676)
Review nits on #2717: the new doc comment had been inserted inside
valid_xref_range's; the tests' xref tables are now one-line literals with
\n escapes, so git diff --check is clean.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz
2026-10-16 22:30:55 +08:00
mtlcl410andClaude Opus 5.5 c6acaefd35 M1: read an xref table numbered from 1 that begins with object 0 (#2676)
Some producers head a classic xref table "1 n" and then write object 0's
free entry first, so every row is one number off and object 1 reads as
free. The renderer coped, but cos did not: printing a scanned invoice
built from cos dropped object 1 (page 1's image) and printed the page
blank. Such a subsection is now read from 0 when its second row locates
an object that is numbered 1, in both xref readers, and the repair is
logged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz
2026-10-16 22:30:55 +08:00
Guillem Hermida 3d567bd732 fix(ui): mode tabs keep the hand over a page scrolled under them (#2755)
With the All tools panel closed, page text scrolled up under the mode bar
gave the Read, Edit, Convert and E-Sign tabs the page's cursor: the
Select tool's I-beam, or Edit text's four-way arrow (the I-beam once a
paragraph was open). The page code tested egui's raw hover position
against the page's whole rectangle, which runs on under the chrome when
the page is scrolled, and it sets the cursor after the mode bar does.

The text layer and Edit text now set their cursor only while the pages'
widget contains the pointer, as Fill & Sign already does; a selection
being dragged keeps the I-beam past the edge. The open paragraph's
editor, a foreground Area placed on its paragraph, also floated over the
tabs and took their clicks: it is now clipped and hit-tested to the
document viewport and stays on its paragraph instead of being pushed
back into the window.

Fixes #2755
2026-10-16 16:27:41 +02:00
aiongg a18aa1414c Integration: #2793 parity notes say malformed Decode keeps the default mapping 2026-10-16 14:24:04 +00:00
aiongg 832402ba64 Integration: #2809 the Read mode command applies an open paragraph
switch_mode put the tool down by assigning Select, so Ctrl+H/⌃⌘H from Edit text left the
paragraph editor open and unapplied in Read mode.
2026-10-16 14:24:04 +00:00
aiongg 934a10740d Merge track r1-core (fredapps-r1)
ROADMAP.md, docs/roadmap.md: keep next's status line
2026-10-16 14:17:52 +00:00
aiongg 7a52541347 Merge track r1-forms (fredapps-r1)
ROADMAP.md, docs/roadmap.md: keep both sides' progress-log lines and revision rows, once each
2026-10-16 14:12:24 +00:00
aiongg 2f8bdf22b8 Merge track r1-app (fredapps-r1)
ROADMAP.md, docs/roadmap.md: keep next's status line; keep both progress-log entries
2026-10-16 14:12:15 +00:00
aiongg 8898d0c9e5 Merge track r1-edit (fredapps-r1) 2026-10-16 14:11:53 +00:00
aiongg 8ef7e42377 Merge track r1-view (fredapps-r1) 2026-10-16 14:11:52 +00:00
aiongg d98b83fdce Merge track r1-output (fredapps-r1) 2026-10-16 14:11:52 +00:00
Guillem Hermida 021812b6ee fix(ui): the password prompt takes typing on Linux again (#2818)
The prompt's field requested focus on every frame. In egui 0.36 each
request also interrupts the input method, and egui-winit answers with
set_ime_allowed(false) then (true), which recreates the X11 input
context (or re-enables Wayland text-input) every frame. On Linux typed
keys go through the input method, so nothing typed reached the field.

Request focus only when the field doesn't have it, as the command
search does (#1638). The permissions password prompt shares the box.

Tests type through synthetic IME pre-edits and commits after opening
an encrypted file from the command line, File > Open, the start page
and a drop, and into the permissions prompt; both fail without the fix.
2026-10-16 16:08:17 +02:00
Guillem Hermida 27a2ac47cf fix(ui): the header, footer and watermark previews show the page under the marks (#2837)
The Header and Footer, Watermark and Background dialogs drew their
preview on a blank sheet, so you could not see where the marks would
land on the page's text and pictures. The preview now paints the page's
own thumbnail, rendered off the UI thread like the pages panel's, with a
blank sheet until it arrives. It shows the current page when the page
range selects it, otherwise the first page the range selects, at its
displayed size (after /Rotate), which is the frame the engine lays the
marks out in. A background colour tints the page picture instead of
covering it, as a background behind the content looks.

Fixes #2837.
2026-10-16 16:04:41 +02:00
aiongg d8a4a055b9 Merge PR #2604: fix(xfa): a page area without <occur> has no limit 2026-10-16 14:04:02 +00:00
aiongg bf240b612c Integration: #2688 drop the formula-cell and TSV-export sentences from the xfdf README and form.data-xml-csv-txt notes 2026-10-16 14:04:02 +00:00
aiongg 24b5060c1f Merge PR #2688: M6: distinguish CSV header tabs from TSV delimiters
ROADMAP.md: next's file; the PR's progress line and revision row added once; status-line edit dropped.
docs/roadmap.md: next's file; the PR's revision row and M6 milestone sentence added once; status-line edit dropped.
crates/xfdf/README.md: all three paragraphs kept (#1917, #2686, this PR).
crates/xfdf/src/tests.rs: #2686's test and this PR's two tests all kept.
parity/acrobat-features.toml: form.data-xml-csv-txt keeps every evidence entry and note.
2026-10-16 14:03:59 +00:00
aiongg 2d5809b7a6 Integration: #2809 opening a document into Read mode puts the tool down 2026-10-16 14:03:56 +00:00
aiongg e56dede417 Merge PR #1919: M4: respect indirect page rotations when reading and editing
ROADMAP.md: next's file plus this PR's 2026-10-13 progress line and revision row; the #1919 refresh line and the status line repeating an M13 item dropped
docs/roadmap.md: next's file plus this PR's revision row; its refresh status line and the refresh note in the M4 row dropped
2026-10-16 14:03:45 +00:00
aiongg 834495382d Merge PR #2686: M6: preserve complete plain XML form values
ROADMAP.md: next's file; the PR's progress line and revision row added once; status-line edit dropped.
docs/roadmap.md: next's file; the PR's revision row and M6 milestone sentence added once; status-line edit dropped.
crates/xfdf/README.md: both paragraphs kept (#1917 export whitespace, this PR's plain XML import text).
parity/acrobat-features.toml: form.data-xml-csv-txt keeps both evidence entries and both notes.
2026-10-16 14:03:31 +00:00
aiongg 70abceba0d Merge PR #2267: fix(filters): preserve output-limit errors in raw Flate fallback
ROADMAP.md: next's revision history plus this PR's row; the #2267 refresh progress line dropped
docs/roadmap.md: next's revision history plus this PR's row; refresh wording dropped from the status line and the M1 row
2026-10-16 14:03:27 +00:00
aiongg eb7e0d9d3e Merge PR #2809: fix(ui): Read mode hides the quick toolbar (#2646) 2026-10-16 14:03:20 +00:00
aiongg e1a1d4211e Integration: #2638 a new drag over copied text shows the action bar again 2026-10-16 14:03:20 +00:00
aiongg 3fd58fc558 Merge PR #1917: M6: preserve whitespace in XML and XFDF attributes
ROADMAP.md: next's file; the PR's progress line and revision row added once; refresh line and status-line edits dropped.
docs/roadmap.md: next's file; the PR's revision row and M6 milestone sentence added once; refresh note and status-line edit dropped.
2026-10-16 14:02:53 +00:00
aiongg 7063c113f1 Integration: #2793 export images with a malformed Decode using the default mapping
A Decode of the wrong length or with a non-number entry made Save Image As
fail and Export All Images skip the image, which earlier versions exported.
2026-10-16 14:02:52 +00:00
aiongg c4bd091eeb Integration: #2544 say that only the mode is copied to the staging file 2026-10-16 14:02:52 +00:00
aiongg fcab31b764 Merge PR #2544: A save keeps the permissions of the file it replaces 2026-10-16 14:02:47 +00:00
aiongg 6b3aade2eb Integration: #2699 describe the read-only refusal in the Windows staging test 2026-10-16 14:02:44 +00:00
aiongg 145896d7e8 Merge PR #2699: M1: saving refuses to replace a read-only file (#2658) 2026-10-16 14:02:36 +00:00
aiongg 7d69b6ebc7 Merge PR #2580: Encryption: /Perms limits what an edited /P allows in AES-256 files 2026-10-16 14:02:36 +00:00
aiongg a463e32eef Integration: #2717 move the valid_xref_range doc comment back above its function 2026-10-16 14:02:33 +00:00
aiongg c198fbb509 Merge PR #2638: fix(ui): Copy in the selection action bar closes the bar 2026-10-16 14:02:30 +00:00
aiongg 6431fdfb88 Merge PR #2703: Go to page brings the page into view horizontally too
crates/ui-egui/src/canvas.rs: goto branch keeps #2595's clamped vertical offset, then #2703's horizontal block
2026-10-16 14:02:30 +00:00
aiongg 1a773e8098 Merge PR #2717: M1: read an xref table numbered from 1 that begins with object 0 (#2676)
crates/cos/src/document.rs: union with #2525: header_relative revisions, the renumbering log line, and log passed to read_section on the first try and the header-relative retry
2026-10-16 14:02:26 +00:00
aiongg 0c0995b62e Merge PR #2595: M3: a page jumped to in single-page view no longer hops into place
crates/ui-egui/tests/view.rs: kept #2587's two tests and #2595's test, all after single_page_layout_shows_one_page_at_a_time
2026-10-16 14:02:21 +00:00
aiongg 2366b0c513 Merge PR #2710: fix(edit): wrap single turned rows at the page margin (#2578) 2026-10-16 14:02:18 +00:00
aiongg 53b8fda93f Integration: #2532 save the structure-tree test without object streams
The default save packs annotation dictionaries into compressed object
streams, so the URL and comment-text byte checks passed without the fix.
2026-10-16 14:02:18 +00:00