Commit Graph
3518 Commits
Author SHA1 Message Date
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
mtlcl410andClaude Opus 5.5 9194ec457f M7: the paragraph editor draws on its page only (#3061)
A paragraph running past its page's bottom edge, as HTML-to-PDF converters
write when they rely on the page clip, opened in an editor that covered the
next page with its box and text, and paragraph outlines crossed the gap
between pages. The editor is clipped to its page within the document area
(it also covered the tool bars when scrolled up), and outlines to their page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz
2026-10-19 00:38:46 +08: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
NetterSilverandClaude Haiku 5.5 31373819f2 Zero-pad required integer digits in FormCalc Format()
Found while testing crates/js/src/formcalc.rs:2240-2276 ("format" builtin, number branch)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-18 16:20:32 +00: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
mtlcl410andClaude Opus 5.5 3f543ca17f M8: redaction drops OBJRs of elements reached only through the parent or ID tree (#2447)
Follow-up to #2532 (review by aiongg): the structure-tree walk started
only at the root's /K, so an element listed only in /ParentTree or
/IDTree kept its object reference to a removed link or comment, and the
root kept that annotation reachable in a full rewrite. The walk now
also starts from both trees and follows their nodes (/Nums, /Names,
/Kids), written in place or as their own objects.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv2WwdgjmBz33GWkwgNn3Q
2026-10-19 00:09:17 +08:00
wstock a2bc0d3570 lopdf: a rebuilt trailer's /Root must match its generation (#2365 review)
usable() and is_catalog() checked the object number only, so a later stream
with /Root 1 1 R outranked the trailer naming 1 0 R; get_offset then found no
such object and Document Properties lost the catalog. cos resolves by number
alone, so its rank needs no change.

Test: inspect::tests::rebuilt_file_prefers_a_trailer_whose_root_is_the_catalog
2026-10-18 16:05:33 +00:00
PerchAnton e75551ce62 M1: reject partial resource-fork copies and integrate current main 2026-10-18 19:03:07 +03:00
NetterSilverandClaude Haiku 5.5 61632e4899 Treat CRLF as a single line break in fonts::wrap
Found while testing crates/fonts/src/lib.rs:79 (wrap_with: `text.split(['\n', '\r'])`)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-18 16:01:48 +00: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
wstock d75d440ad9 lopdf: a rebuild prefers a trailer whose /Root is the catalog (#2365 review)
The mirror of the cos change for render::inspect: a later cross-reference
stream whose /Root points at /Info replaced the earlier trailer, and Document
Properties lost the catalog. A candidate whose /Root is /Type /Catalog or has
/Pages now wins; another dictionary is still taken when nothing better is
there (FDF).

Test: inspect::tests::rebuilt_file_prefers_a_trailer_whose_root_is_the_catalog
2026-10-18 15:23:38 +00: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
jonathanwxh-cell d76516219d M2: keep hidden ActualText fixture outside CropBox (#2838) 2026-10-18 23:09:40 +08:00
jonathanwxh-cell 2714f9e54f automation: report effective validated PDF version in doc_optimize (#3090) 2026-10-18 23:09:09 +08:00
sanches 2b445950df Merge remote-tracking branch 'origin/main' into i18n-id-vi 2026-10-18 18:08:27 +03:00
PerchAnton 0910b8314a M12: retain product notes while integrating current main 2026-10-18 18:07:15 +03:00
wstock e336b48a35 cos: a rebuild prefers a trailer whose /Root is the catalog (#2365 review)
A later cross-reference stream (or trailer) whose /Root points at another
dictionary, such as /Info, replaced an earlier good trailer, and a full save
then wrote that dictionary as /Root. A candidate whose /Root passes the
root_is_catalog rule (/Type /Catalog or /Pages) now beats one whose /Root is
only some dictionary, wherever it is in the file. The looser rule still
applies when nothing better is there, which FDF files (whose /Root has
neither key) and the repair path for a non-catalog /Root rely on.

Test: reconstruction_skips_a_trailer_whose_root_is_not_the_catalog
2026-10-18 15:06:31 +00:00
mtlcl410andClaude Opus 5.5 6be953459c fix(print): the options read ends at its deadline and a dead read wakes the dialog (#1818)
Review follow-up on #2108:
- output_within waited on the reader thread with join, so a process the
  command started could hold the output pipe, and the wait, long past the
  limit after the command exited or was killed. The output now comes back
  over a channel with recv_timeout; such a reader finishes on its own.
- the printer-list and options workers ask for a frame from a guard
  dropped on exit, also when the source panics, so an idle dialog sees
  the closed channel without waiting for another event.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz
2026-10-18 23:03:31 +08:00
mtlcl410andClaude Opus 5.5 b59b91f0be fix(print): Vietnamese for the printer-options loading note (#1818)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz
2026-10-18 23:03:31 +08:00
mtlcl410andClaude Fable 5.1 e3847ba076 fix(print): pass the lpoptions limit outside the stand-in command in the CUPS test
The limit landed inside `command(...)` in one Unix-only test, which this
Windows machine never compiles; checked now with a Linux target.

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
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
Marco Arnulfo 6ee8329ec0 test(ui): the reduced-copy regression saves a real PDF and reopens its text (#2150) 2026-10-18 17:03:20 +02:00
PerchAnton 4f4f589365 M12: retain product notes while integrating current main 2026-10-18 18:02:45 +03:00
mtlcl410andClaude Opus 5.5 024407992d style: cargo fmt
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv2WwdgjmBz33GWkwgNn3Q
2026-10-18 22:56:57 +08:00
aiongg 40d7b0bc47 Merge upstream main a12fe8f41 into next 2026-10-18 14:56:01 +00:00
Marco Arnulfo b913c2851d fix(ui): a second file dialog waits for the open one instead of being refused (fixes #2150) 2026-10-18 16:53:23 +02: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
jonathanwxh-cell 87e68246c8 style(render): rustfmt CropBox condition (#2838) 2026-10-18 22:43:01 +08:00
PerchAnton 57c5dde167 M7: preserve rotation and index regressions on current main 2026-10-18 17:39:44 +03:00
jonathanwxh-cell c6bf3d0dbd fix(render): avoid emitting full ActualText replacement when span is partially cropped (#2838) 2026-10-18 22:39:15 +08:00
alehelandClaude Opus 5.5 23ed4cca65 M3: All tools view keeps Escape for dialogs, leaves with the mode option, and searches Arabic
Review follow-ups for the expanded All tools view:

- Escape closed the view even when a dialog or prompt over it owned the key.
  It now checks modal_open() first.
- set_option("mode", …) changed workspace without clearing the view, so
  leaving and coming back to All tools reopened it. Another workspace now puts
  it away, as switch_mode does.
- Right-to-left translations are stored in display order, so a multi-word
  Arabic query typed in logical order missed its tool. Such a query now matches
  word by word, as the command palette's search does.

Each test was seen to fail with its fix reverted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 16:33:12 +02:00
PerchAnton e45a1db89f M1: reject partial resource-fork copies and integrate current main 2026-10-18 17:30:26 +03:00
alehelandClaude Opus 5.5 eca16e6bd5 fix(edit): backdrop copies keep the stream dictionary and every slot
Review of #2815 (CodeRabbit):

- A content stream whose bytes live in an external file (`/F`) draws
  those, not its inline bytes, so it is never taken for a backdrop.
- The copy keeps the original stream dictionary, unknown entries
  included, less `Length` and `DL` (Flate re-encodes it); it had started
  from an empty dictionary.
- Every `/Contents` slot that lists the original stream gets the copy: a
  page listing the same stream twice painted the white fill again over
  the background.
- The Background dialog starts with replacing on each time it opens.
  Update restores backdrops before re-applying, so a replaced page shows
  no fill and no checkbox, and a choice left off from an earlier dialog
  hid the background again unseen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 16:24:14 +02: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
jonathanwxh-cell b2727ac15b M2: refresh footnote reference line selection against current main (#2960) 2026-10-18 22:22:19 +08:00
jonathanwxh-cell 76d1bea652 M2: refresh CropBox text clipping against current main (#2838) 2026-10-18 22:17:35 +08:00
alehel 522c1dcd22 Merge remote-tracking branch 'origin/main' into feat/all-tools-expand-view
# Conflicts:
#	ATTRIBUTION.toml
2026-10-18 16:17:28 +02:00
jonathanwxh-cell 6c611edc61 M2: refresh clip-mode text extraction against current main (#3116) 2026-10-18 22:14:54 +08:00
mtlcl410andClaude Opus 5.5 4899072089 fix(forms): read dynamicRender only from the configuration packet itself (#3180)
Review follow-up: in a whole-XDP stream, a config/acrobat/acrobat7/
dynamicRender path inside xfa:datasets/xfa:data came before the real
config packet and decided the form type. The lookup now follows direct
children only: the config child of the xdp root (or the config packet
itself), then acrobat, acrobat7 and dynamicRender.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv2WwdgjmBz33GWkwgNn3Q
2026-10-18 22:14:02 +08: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
Ozt-y 4945677717 fix(content): restrict '>EI' terminator detection to ASCIIHex filter 2026-10-18 19:32:09 +05:30
jonathanwxh-cell ff5a2fc9eb M2: retain clipping text in filtered extraction (#3116) 2026-10-18 22:00:21 +08:00