6290 Commits
Author SHA1 Message Date
Grzegorz MartensandClaude Opus 5.5 8c5333bfe7 M7: font reads decode through a view of the stream, and refuse before resolving its parameters
CodeRabbit's review of 674a20899:

- Each budgeted read of a font's stream went through
  `Document::with_direct_parms`, which copies the whole stream when its
  /DecodeParms is given by reference: an unrelated value in the
  dictionary, however large, was copied again for every read.
  `DecodeBudget::decode_stages_within` now takes the document and reads
  through `Document::decoding_view`, as `decode_strict` and
  `decode_with_damage` do: the data is shared, and only /Filter and the
  parameters made direct are copied. `Reads::decode` and the editor's
  program read use it, a Type 3 font's glyph descriptions read through
  `decode_with_damage`, and so does Repair Thai maps' program read.
- A Type 3 font's glyph descriptions resolved one description's
  parameters a font before the spent allowance refused it. They now ask
  `DecodeBudget::refuses` first, as `decode_stages_within` does for the
  others: once the allowance is spent a stream with data is refused, and
  noted, before its parameters are resolved.
- `DecodeBudget::refused` counts the decodes refused for want of the
  allowance, where `remaining() == 0` can't tell a refusal from an
  allowance spent to the byte.

Test: `reading_a_fonts_streams_copies_no_dictionary` (`pdfcraft-fonts`,
a test binary of its own): a font whose program and ToUnicode hold an
unrelated array of a million numbers and /DecodeParms by reference is
read eight times by the editor's program read and the metrics read,
and the process's peak grows by less than half of what one array
holds. That a Type 3 font refuses before resolving parameters changes
no result, only the time it takes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
2026-11-09 21:45:10 +01:00
eliets2andeliets2 a1ea2d3763 Align stream decode cap with renderer at 256 MiB (#6585)
Editor, export and redaction must not read or rewrite text that the page view and Find never see, which a mismatched cap allows on large streams.

Lower MAX_DECODED to 256 MiB to match the renderer cap, so every Stream::decoded-based content reader stops at the same byte and oversized streams error instead of exposing later text.

Test: decoded_stops_at_renderer_cap_of_256_mib failed before the change and passes after.

Co-authored-by: eliets2 <287273517+eliets2@users.noreply.github.com>
2026-11-09 18:54:53 +01:00
Grzegorz MartensandClaude Opus 5.5 674a208990 M7: a test pins that Repair Thai maps refuses a map that isn't Identity
The Legal forms review of b7224cbc9..4d6ff291d:

- Nothing pinned that `recovered_thai_map`'s rewritten guard still
  refuses a /CIDToGIDMap that isn't Identity: deleting it left every
  Thai test passing. `recovered_thai_map_checks_every_kept_glyph_against_
  the_font_program` now asserts no map for a map stream that moves glyphs
  and for another name.
- The guard's comment and the test's cited Identity as the default of
  ISO 32000-2 Table 115. It is the default of PDF 1.x (ISO 32000-1);
  PDF 2.0 gives it none and requires the map with a /FontFile2. Both now
  say so, and that the renderer takes a missing map as Identity too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
2026-11-09 17:18:51 +01:00
Grzegorz MartensandClaude Opus 5.5 ed6af22b85 redact: the README says a value read through another generation may be read again
Since 0a00862e9, what an image is stored again with (its size, filters and parameters) is
remembered by number and generation, so a value reached through a reference of another
generation is fetched again rather than taken from what the reference of its object's own
generation read. The README's list of what may be read again now says so. What an image names
is still remembered by object number, so a dictionary named that way isn't read again.

The same sentence said a chain of more than 32 references may be read again. `names_in` follows
33 references before it gives up on a chain, as `a_chain_of_references_is_named_to_the_limit`
says, so it is more than 33.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
2026-11-09 17:02:56 +01:00
Grzegorz MartensandClaude Opus 5.5 ce2db2a319 M8: the redaction README says a name a form without resources draws stays
The Consumers review of 64dfe1fd4. The README said a surviving form loses
the resource entries for removed XObjects its own content does not draw.
It also keeps those a form without resources of its own, drawn through
them, still draws, and since this PR a redacted page keeps them the same
way.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
2026-11-09 16:55:36 +01:00
Grzegorz MartensandClaude Opus 5.5 4d6ff291d7 M7: Reads::decode says what a stage past its limit is charged
The Claims review of the description at b7224cbc9. `Reads::decode` said a
stream past its limit is unread, not refused, "when what is left can pay
for its stages". What `DecodeBudget::decode_stages_within` does, and
`a_stage_past_its_limit_charges_what_came_before_and_the_limit` pins:
with more left than what the stages before the stopped one made and the
limit, it is charged those two; otherwise, with more left than the
stages' total (behind one filter, the limit), it is charged that total;
with no more left than that total, it spends all of it and counts as
refused.

`MAX_THAI_PROGRAMS` also names the second read of a subset's program,
for which of its glyphs have outlines, among what it pays for.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
2026-11-09 16:52:47 +01:00
Osvaldo Duran MelendezandClaude Sonnet 5.5 a50b52ea84 Merge upstream/main into pr/print-area
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-09 10:50:00 -05:00
Grzegorz MartensandClaude Opus 5.5 92e8e6eff0 M7: Repair Thai maps reads a /CIDToGIDMap given by reference, and takes a missing one as Identity
The Consumers review of ba28458ad..b7224cbc9:

- `recovered_thai_map` read the descendant's /CIDToGIDMap with
  `Dict::name`, on the line after e9142b03b's /Encoding check, so a map
  given by reference made Repair Thai maps pass the font over, and so
  did a missing one, which is Identity (ISO 32000-2 Table 115), as
  `composite_glyph_maps`, `LegacyThaiFont` and the renderer read it. It
  now resolves the map and takes a missing one as Identity.
- `MAX_THAI_PROGRAMS` says what it pays for: the programs, and the CMaps
  and glyph maps read to adapt their cmaps. The metrics read to find and
  measure the subsets aren't charged to it. Its refusal ("MiB of font
  data") still says what it counts.

Test: `recovered_thai_map_checks_every_kept_glyph_against_the_font_program`
recovers the same map with the font's /CIDToGIDMap given by reference and
with none.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
2026-11-09 16:48:01 +01:00
Grzegorz MartensandClaude Opus 5.5 650419766b Merge main again into fix/jbig2-dictionary-any-route
One conflict, in redact lib.rs: the module list, where main added `elsewhere` and
`identification` (#6714) and this branch `globals`. All three stay, in order.

Main's #2448 work also added a sixth step to `apply`, after the verification and the pattern
guard: `metadata::scrub` removes the `/Info` entries and the catalog's and pages' XMP that repeat
the removed text. An image that only such a packet refers to leaves the file then, after
`unshare` had looked for what left, so its shared dictionary stayed. `unshare` now runs after
the scrub, last of what can take something out. Storing images again changes no page's content
and no pattern cell, so the verification and the pattern guard before it check the same pages
they did. The crate's doc says the dictionary goes last. Remove Hidden Information's order is
unchanged: main's changes to `sanitize.rs` only read (`owned_values`).

Test: `an_image_only_the_scrubbed_metadata_refers_to_takes_a_shared_jbig2_dictionary_too`. An
image under the mark is also named by the catalog's XMP, which repeats the text removed beside
it. After the redaction the packet is gone, the image on the other page is stored again, and
the dictionary is gone too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
2026-11-09 16:41:19 +01:00
Grzegorz MartensandClaude Opus 5.5 64dfe1fd44 Merge main again into fix/redact-prune-through-forms
A third merge of main, at ba28458ad. Main's #2448 (in #6714) collects
the text a redaction removes from the walk's scope, which this branch
also reads after the walk for what it left of the page's allowance.

- `interp.rs`: `Scope` keeps this branch's `into_budget` and gains
  main's `with_removed_room`, `flush` and `removed`.
- `lib.rs`: the page's walk starts with main's room for removed text,
  and after it the scope's removed text is collected as on main, then
  what it left of the page's allowance is taken for the cleanups, last,
  as taking it consumes the scope.

Main's new code reads no content stream or form in the walk or the
cleanups, so nothing of this branch's allowance or one-operator reads
needed carrying into it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
2026-11-09 16:32:21 +01:00
Grzegorz MartensandClaude Opus 5.5 b7224cbc9a Merge main again into fix/fonts-decode-budget
A third merge, of ba28458ad, with nothing to resolve. main's commits since
b6cbf9bb3 add no font program, metrics or CMap read in pdfcraft-fonts or
the editor's font code for this PR's allowance to cover.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
2026-11-09 16:31:54 +01:00
Grzegorz MartensandClaude Opus 5.5 e9142b03b9 M7: a composite font's /Encoding is read through a reference
The Legal forms review of 8fb534ad4. A Type 0 font's /Encoding may be
given by reference (a name or a CMap stream, either indirect), and the
metrics read resolve it: an indirect /Identity-H reads two-byte codes.
The editor's check before reading a composite font's metrics, and
`main`'s `composite_glyph_maps` and `recovered_thai_map`, read it with
`Dict::name`, which doesn't resolve: such a font counted as another
encoding, so the editor adapted no copy of it and Repair Thai maps
passed it over. All three now read it through `identity_h`, which
resolves it as the metrics do.

Tests: `a_composite_fonts_encoding_given_by_reference_is_read` (the
editor adapts a copy of a composite subset with `/Encoding 5 0 R`, object
5 `/Identity-H`, that maps 'Ω', and its metrics read two-byte codes), and
`recovered_thai_map_checks_every_kept_glyph_against_the_font_program`
recovers the same map with the font's /Encoding by reference.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
2026-11-09 16:27:49 +01:00
BFlat ba28458ad8 M3: a password prompt keeps a place in the open queue for its retry (#6731) 2026-11-09 22:21:21 +07:00
Grzegorz MartensandClaude Opus 5.5 587d6528b0 redact: the refusal test checks a copy with its filter by reference too
In `a_shared_jbig2_dictionary_that_cant_leave_refuses_the_redaction`, the case of a copy of
the dictionary whose `/Filter` is given by reference may end `Ok`, the image stored again
without it. That branch checked only that the dictionary, object 9, left, and that its marker
was nowhere in the file. But `assert_gone` can't decode the copy, object 10, with its filter by
reference, and its bytes are Flate, so a run that never found the copy, and left it in the
file, passed. The branch now checks that object 10 left too, through `reachable_objects`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
2026-11-09 16:20:40 +01:00
BFlat 5aae0c3b82 Merge pull request #6714 from storytold/merge/ui-print-optimize2
Land print production, viewer, attachment and optimizer changes (#1918, #1998, #2539, #2348, #2701, #3806, #4139, #4378, #4401, #4763, #5259, #5508, #5316, #4434, #4440, #6092, #6098)
2026-11-09 22:20:37 +07:00
bflatastic c45ac1a873 Merge main into merge/ui-print-optimize2
# Conflicts:
#	crates/ui-egui/src/app/files.rs
#	crates/ui-egui/src/tools/forms_ui.rs
2026-11-09 22:03:08 +07:00
BFlat d2139e58ae Merge pull request #6716 from storytold/merge/xfa2
Land XFA layout, scripting and form fixes (#3589, #4336, #4359, #4517, #4537, #4608, #4662, #4664, #4784, #4791, #5010, #5122, #5124, #5153, #5225, #5368, #5369, #5370, #5393)
2026-11-09 22:02:14 +07:00
bflatastic 302b61c7e3 Fit the landed changes together: the highlight test batches value edits, since a form-script event can't be batched 2026-11-09 21:43:02 +07:00
bflatastic e52b2de518 Fit the landed changes together: the full-screen note test expects its pop-up, and the lock-question test turns the signature tool on before opening the Sign menu 2026-11-09 21:42:59 +07:00
bflatastic 36e7121ab0 Merge main into merge/ui-print-optimize2
# Conflicts:
#	crates/render/src/inspect.rs
#	crates/render/src/lib.rs
2026-11-09 21:16:23 +07:00
bflatastic 16b57d6a91 Merge main into merge/xfa2
# Conflicts:
#	crates/engine/src/tests.rs
2026-11-09 21:15:35 +07:00
BFlat fe3879bc88 Windows gate: the owner-rights test allows an elevated run to replace the list, if it then restricts the file (#6729) 2026-11-09 21:14:18 +07:00
BFlat 2c30c14e10 Merge pull request #6713 from storytold/merge/comments-annot2
Land comment groups, appearance defaults, callout parts, pop-ups and stamp lines (#4358, #4365, #4094, #2137, #2345)
2026-11-09 21:14:02 +07:00
bflatastic 62b8a2c326 Fit the landed changes together: compare the node's name as text 2026-11-09 21:13:26 +07:00
bflatastic a460022c20 Fit the landed changes together: compare an XFA node's name without a needless reference 2026-11-09 21:10:40 +07:00
bflatastic 5f860fb5ff Fit the landed changes together: the XFA split's break search gets its own function, keeping it under clippy's complexity limit 2026-11-09 21:06:46 +07:00
bflatastic f822505250 Fit the landed changes together: the rotation keys get their own function, keeping the shortcuts under clippy's complexity limit 2026-11-09 21:04:55 +07:00
Combiler01 acae521115 fix(print): robust custom dimension parsing, spool media option fallback, driver paper bounds and name resolution 2026-11-09 19:33:31 +05:30
bflatastic 3774c3312a Fit the landed changes together
The forms editor's test draft sets the focus's obj and list, which main added, and the focus scripts look up the focused field with focused_field so a same-name twin is read as main reads it.
2026-11-09 21:03:12 +07:00
bflatastic 2af11131ef Merge main into merge/xfa2
# Conflicts:
#	crates/automation/src/tools.rs
#	crates/automation/tests/it/automation.rs
#	crates/forms/src/tests.rs
#	crates/ui-egui/src/tools/forms_ui.rs
#	parity/acrobat-features.toml
2026-11-09 20:57:05 +07:00
bflatastic 2ce2d3cf81 Merge main into merge/ui-print-optimize2
# Conflicts:
#	crates/automation/src/redact.rs
#	crates/automation/src/tools.rs
#	crates/print/src/lib.rs
#	crates/render/src/inspect.rs
#	crates/render/src/lib.rs
2026-11-09 20:56:15 +07:00
bflatastic 856d3fb0ac Merge main into merge/comments-annot2
# Conflicts:
#	crates/render/src/inspect.rs
#	crates/render/src/lib.rs
#	crates/ui-egui/src/canvas/page_pointer/tests.rs
#	crates/ui-egui/tests/it/comments.rs
2026-11-09 20:56:09 +07:00
Combiler01 a1cc08ab03 chore: format print tests and lock winprint dependency 2026-11-09 19:09:56 +05:30
Combiler01 80420ee9d6 Merge remote-tracking branch 'upstream/main' into fix/paper-size-driver-5861 2026-11-09 18:50:47 +05:30
Grzegorz MartensandClaude Opus 5.5 8fb534ad4c M7: tests pin what a stage past its limit charges the allowance
Mutation testing of 063f8629e missed eight mutants in
`DecodeBudget::decode_stages_within`: nothing pinned what a read
stopped at a stage's limit, at the stages' total or at what is left of
the allowance charges, which limit it reports, or where one case gives
way to the next.

`a_stage_past_its_limit_charges_what_came_before_and_the_limit` reads
each way, and each boundary on both sides: a byte more room than the hex
stage and the limit (charged them, a byte left), exactly that (past the
allowance: all of it spent, its limit reported), a hex stage making
exactly the limit so the Flate stage reaches the stages' total with more
left (charged the total), with exactly the total left of a larger
allowance and with less (spent, the allowance's limit reported), and,
with nothing left, a stream with data that decodes to nothing (refused)
and an empty one (read).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
2026-11-09 14:08:29 +01:00
Grzegorz MartensandClaude Opus 5.5 509cf9f9fd M7: the editor reads no metrics for a composite font it can't adapt
The Resources review of 8eead8ecd:

- `embedded_sfnt_within` read a composite font's metrics within the
  editor's allowance before `composite_glyph_maps` refused any `/Encoding`
  but Identity-H, so an Identity-V or UniJIS font spent its ToUnicode and
  `/CIDToGIDMap` for nothing. Its `/Encoding` is now checked first; a
  program with a cmap of its own is kept as it is, as when the rebuild
  finds nothing.
- The Thai edit's allowance, `MAX_THAI_PROGRAMS`, now also pays for the
  CMaps and glyph maps its subsets' metrics and codes are read from: its
  doc and its refusal say "font data", not "font programs".
- `a_symbolic_truetype_font_without_an_encoding_reads_its_glyph_names`
  also reads its font, whose `post` table names its glyphs, within an
  allowance: the program is paid for by the glyph-name reading, by the
  Mac OS Roman one and for the widths, and a byte short of the first the
  names go unread.

Tests: `a_composite_font_that_cant_be_adapted_spends_only_its_program`,
and `adapting_a_programs_cmap_is_paid_for` again expects a composite font
whose codes aren't Identity-H to pay for its program only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
2026-11-09 13:36:44 +01:00
Grzegorz MartensandClaude Opus 5.5 063f8629e4 M7: each filter stage of a font's stream is held to its limit, as without an allowance
The Resources review of 8eead8ecd. The program read and the metrics reads
passed their limit times the number of filter stages as one total, which
any one stage could use: a FontFile2 of Flate making 128 MiB of
whitespace, under seven ASCIIHex stages (a 130 KB file), made all of it
before being refused, about 0.1 s a font where `main`'s bound stopped it
at 16 MiB. `edit`'s `matching_thai_outline` reads such a program for each
of a page's fonts with no total, and every `Metrics::from_dict` up to
three times.

Now each stage is held to the limit, as a decode without an allowance
holds it, and the stages together to the limit for each of them, so every
stream the stage scaling was for still reads: a full `/CIDToGIDMap` or a
12 MiB program behind ASCIIHex and Flate. The two bounds take an entry
point of their own: `pdfcraft_filters::decode_tolerant_counted_each`,
which `run` already supports, and `DecodeBudget::decode_stages_within`,
which `Reads::decode` and the editor's program read use. A stage past the
limit is charged what the stages before it decoded and the limit; past
the stages' total, or past what is left, it is charged as
`decode_within` charges. The program, the last stage, is so within the
limit without a check of its own.

Tests: `each_stage_is_held_to_its_own_bound_within_the_total` in
`pdfcraft-filters` (a Flate stage stopped at its bound hands the next
stage nothing), `each_stage_is_held_to_the_limit` in `pdfcraft-cos`, and
in `pdfcraft-fonts` `an_editors_program_read_holds_each_stage_to_its_limit`
and `each_stage_of_a_metrics_stream_is_held_to_its_limit`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
2026-11-09 13:36:29 +01:00
Grzegorz MartensandClaude Opus 5.5 b9fda64bb6 Merge main into fix/redact-prune-through-forms
A second merge of main, at b6cbf9bb3. Nothing needed resolving.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
2026-11-09 13:08:31 +01:00
Osvaldo Duran Melendez 924b435256 Merge remote-tracking branch 'upstream/main' into pr-fix/print-area 2026-11-09 07:07:01 -05:00
Grzegorz MartensandClaude Opus 5.5 d4abe80671 Merge main again into fix/fonts-decode-budget
main's #3962 (symbolic TrueType glyph names, 63a6f8ace and nearby) reads a
symbolic TrueType font's codes by the `post` names of the glyphs its cmap
selects, before the Mac OS Roman reading:

- crates/fonts/src/pdf.rs, `unicode_map`: both readings stay, in main's
  order, each given the metrics read's allowance. The program read main
  added (`symbolic_glyph_texts`) goes through `Reads::decode`, as
  `symbolic_mac_roman_texts` does since the last merge: paid for from the
  allowance, `past_allowance` set when it can't be, behind several
  filters within the stream's own limit.
- crates/fonts/src/pdf/tests.rs: both sides added tests at the same place;
  all are kept.

Tests: `adapting_a_programs_cmap_is_paid_for` now expects the program to
be paid for a fourth time, and `the_symbolic_mac_roman_reading_is_paid_for`
becomes `the_symbolic_readings_of_a_program_are_paid_for`, paying for both
readings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
2026-11-09 13:06:32 +01:00
Osvaldo Duran MelendezandClaude Sonnet 5.5 447d9f0267 Merge upstream/main into pr/print-area
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-09 07:06:24 -05:00
Grzegorz MartensandClaude Opus 5.5 b9e83d8b67 Merge main again into fix/jbig2-dictionary-any-route
One conflict, in redact sanitize.rs. Main's #6021 (930b44131) split `remove_hidden` in two:
- it now counts only what the chosen categories need (`scan_only`);
- it hands the removal to `remove_counted`, which tests also call with `every_page`.

This branch had added one line to the old body: `kept_before`, what a full save keeps before
anything is removed. Main's side is taken whole, and that line is now the first thing
`remove_counted` does after finding the catalog, before any change to the document. So every
caller of `remove_counted` has it. `unshare_unmarked` stays last, after `unlink_undrawn`, and
merged cleanly there. The only early return after a change is `NothingToApply` when nothing
was removed and nothing unlinked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
2026-11-09 13:05:41 +01:00
Grzegorz MartensandClaude Opus 5.5 4cc0abbe62 M8: a test that each form a kept Type 3 glyph draws is walked within an allowance of a page
The merge gave `prune_font_forms`' walk of each Form a kept glyph
draws the allowance of a page, which its call of `resource_ops` now
needs; no test pinned it. In
`the_form_a_kept_type3_glyph_draws_is_walked_within_the_allowance_of_a_page`
such a Form draws two forms without resources of their own, each past
half of the allowance, and the redaction is refused with the decoder's
limit; with two small ones it goes on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
2026-11-09 13:03:50 +01:00
Grzegorz MartensandClaude Opus 5.5 1184738b54 redact: an image stored again keeps the generation its header gives
Main's #1143 (863af864a), merged in 77b9cfa31, has cos accept both generations of a slot whose
cross-reference row and object header disagree: `8 0` in the row and `8 1 obj` in the file, a
reference of either reads the object. `unshare` stored an image again with `Document::set` under
the row's generation, which keeps that one alone. A page that named the image by its header's,
`/Im 8 1 R`, then read null, in the document and after a full save: a redaction on another page
took the image off a page no mark reached.

It now stores it with `Document::set_existing`, which keeps both. It was the one object this
PR's code writes back after reading.

Test: `an_image_stored_again_keeps_the_generation_its_header_gives` patches the second page's
image to `8 1 obj` behind a row of generation 0, and its page to `/Im 8 1 R`. After a redaction
on the first page, that page still draws the scan, in the document and after `write_full` and
reopening, and the dictionary is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
2026-11-09 13:00:28 +01:00
bflatastic fb387d95d9 Fit the landed changes together: the lock-question test opens the Sign menu by its current label 2026-11-09 18:54:56 +07:00
bflatastic 99eaa73ca8 Fit the landed changes together: a double-click on a group member opens the group's pop-up 2026-11-09 18:54:18 +07:00
Combiler01 d4d8a87c17 fix(print): restore papers_loading marker when reusing background worker 2026-11-09 17:22:43 +05:30
bflatastic 28585c01a5 Fit the landed changes together
- engine: the on_changes test's XfaRun literals set highlight; the script
  runner reads its template before borrowing the live form for to_js; has_event
  reads the paged live form, as the rest of the runner does, so focus scripts
  find a page-master copy by its own SOM path.
- js: property reads compare and copy the shared (Arc<str>) node text, and the
  property tests build XHost with its current signature.
- xfa: the Emitter test literal sets groups and used; a field split that is
  undone also restores the names handed out; rustfmt on a merged import.
- parity: drop the use/usehref gap from form.xfa-dynamic, as prototypes are now
  resolved before the template is parsed.
2026-11-09 18:46:50 +07:00
BFlat b6cbf9bb30 Merge pull request #6710 from storytold/merge/forms-links-text2
Land forms, links, find and redaction-save fixes (#4496, #4532, #3567, #3773, #4470, #4474, #4497, #5658)
2026-11-09 19:45:39 +08:00
BFlat 6b56de9ecf Merge pull request #6711 from storytold/merge/render-patches2
Land renderer patches, layer auto state, auto-tag artifacts, export clips and print page lookup (#3969, #4393, #4396, #4410, #4433, #4459, #4159, #5075, #5973)
2026-11-09 19:45:24 +08:00