Commit Graph
4844 Commits
Author SHA1 Message Date
bflatastic d351aa2760 Read Thai font programs and CIDToGIDMaps with DecodeParms given by reference
A predictor whose parameters are an indirect object left its row tags in
the decoded font program and glyph map, so the Thai map repair, the glyph
codes and the shaper read the wrong bytes. Resolve the parameters as the
other font readers do, keeping the decode budgets.
2026-11-08 23:23:09 +07:00
BFlat edc5c757d3 Word tables get outer borders only where the page rules them (#6626)
A grid drawn with inside lines only no longer gets a box in Word.
2026-11-09 00:09:23 +08:00
mtlcl410andClaude Opus 5.5 64dd381bc4 M1: the unlinked-update tests check the objects the update wins with (core.malformed-input-safety)
The hybrid update test now checks that the update's page and catalog
win and that the repair log says why, and that the linked file keeps
both revisions; the save test checks that the reopened file keeps the
update's page and catalog.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
2026-11-09 00:04:59 +08:00
bflatastic ae7a21d2b0 Edit grouped text with one click instead of preparing pages on sight
Edit text queued Prepare grouped text for every page that came into view, after a full
preparation on a copy of the document on the UI thread to see whether it could. Scrolling cost
that work per page, marked the document changed, added undo steps and inlined shared forms
although nothing was edited.

Now nothing happens while pages are shown. A click (press and release, no drag) on grouped
artwork, routed to the picture by the page router as before, asks once whether that artwork
shows text preparation would open (text::forms::grouped_text_at, which reads the page without
copying or changing it). If it does, the page is prepared as one undoable step and the
paragraph at the point clicked opens for typing. A logo or a group preparation would refuse is
selected as before, with no message and no change. A drag still moves the selected group, and
while a paragraph is open or an edit is waiting the click selects as before. text_prepare is
unchanged.

The docs and the parity entry no longer say text is prepared on entering Edit text.
2026-11-08 22:31:14 +07:00
bflatastic cc9f7977bf Repair a page's damaged THSarabunPSK map without grouped text
The repair reads the page's own fonts. It ran only after a group was expanded, so the same
damaged map on text that was never grouped kept reading wrong. Preparation now repairs it
whenever it finds it, recorded in the repair log as before, and PrepareText (text_prepare)
succeeds when it repaired a map even with nothing to expand. A repaired map no longer matches
the damage's fingerprint, so preparing again changes nothing.
2026-11-08 22:31:14 +07:00
bflatastic 90b88ddcb6 Ungroup reads the Do it replaces and refuses one inside text or a path
Ungroup and text preparation now check the placement in one place, ungroup_ops, which is given
the page's operators and the Do's index:

- The form is looked up by the name the Do writes, byte for byte. Ungroup looked it up by the
  picture's display name, a lossy UTF-8 copy, so a form named /F#FF was 'missing'.
- A Do with more than one operand is refused: the picture was read for its first, the renderer
  draws its last.
- A Do inside BT…ET or an unfinished path is refused. Inline, the form's text objects would be
  nested in the page's, and its clip would take in the page's path. Preparation already refused
  these; Ungroup didn't.
2026-11-08 22:31:14 +07:00
bflatastic 233bc6c932 Ungroup keeps the translucency an unmatched Q doesn't restore
A Q with no q before it restores nothing; the renderer ignores it. The check for translucency at
the Do took it as restoring the opaque default, so a transparency group drawn after /H gs Q was
inlined although it is drawn translucent.
2026-11-08 22:31:14 +07:00
bflatastic 7169b0d6ad Ungroup refuses a form the page's default colour space would remap
A form with resources of its own and no /DefaultRGB (likewise Gray, CMYK) draws its device
colours as they are. Inline, the page's resources apply, and a /DefaultRGB there would remap
them (ISO 32000-2 §8.6.5.6). Only the form having an entry the page lacks was refused; now either
side having one the other doesn't share is.
2026-11-08 22:31:14 +07:00
bflatastic 5850000e41 Prepare grouped text with Ungroup's own form expansion
text/forms/expand.rs was a drifted copy of ungroup.rs. It is gone: text preparation now opens each
placement with crate::ungroup, so Ungroup and preparation share one implementation.

What the copy added is now in ungroup.rs: a Refusal that says whether the form itself or only
this placement is the reason (intrinsic) and whether a rename alone was the problem (renaming),
the shows_text result, merges_without_renaming, refusals for unreadable /Resources and /Group
entries and arrays with a non-number, a cap on resource counts and q nesting, a total size for
pattern copies, and ending an unfinished path with the form. Ungroup's newer behaviour stays:
names are read from the operand the renderer uses, so a surplus operand is renamed correctly
rather than refused; default colour spaces are compared with the page's; and a group blending
in DeviceRGB on a page that names no blending space is drawn inline, as Ungroup does, rather
than refused as the copy did.

What a form draws is now read within one decode allowance shared with the form itself, so a
crafted group can no longer make one Ungroup decode 64 MiB for each of 1024 nested forms. A
group whose content can't be checked is refused; for a form without a group, blend modes inside
don't matter, and content that can't be checked only means preparation can't tell whether it
has text (shows_text is None), which it reports.
2026-11-08 22:31:14 +07:00
bflatastic 62b85edef1 Write the Thai glyph check without a negated is_some_and
Clippy's nonminimal_bool asks for is_none_or: a glyph with no outline range, or an empty one, is skipped as before.
2026-11-08 22:31:14 +07:00
bflatastic 4444355446 Merge grouped Thai text editing (#6249)
# Conflicts:
#	parity/acrobat-features.toml
2026-11-08 22:31:13 +07:00
mtlcl410 fae489acdb Merge upstream/main into fix/update-without-prev-is-refused 2026-11-08 23:27:12 +08:00
BFlat 922f18cd8e Fix the build: page_rules joins content streams with text::joined (#6621)
#5154 and #6289 each passed on their own base; together page_rules read content_streams as pairs after it began returning ContentStream.
2026-11-08 23:27:10 +08:00
mtlcl410andClaude Opus 5.5 90b3c41bc6 Merge upstream/main into fix/flate-predictor-untagged-rows
Conflict: crates/edit/src/rules.rs, where main joins the content streams with
crate::text::joined; that line replaces this branch's earlier build fix, so the file is main's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
2026-11-08 23:17:19 +08:00
FredApps 981193ad41 Merge pull request #6619 from FredApps/fix/rules-content-stream-api
fix(edit): restore page rules after the content stream API change
2026-11-08 15:30:47 +01:00
mtlcl410 7d1dea0517 M7: Ungroup draws Form artwork in place, so its text can be edited (#3067)
Refs #2964, #3005
2026-11-08 22:14:30 +08:00
FredApps cb705f73de M0: restore page rules after the content stream API change 2026-11-08 14:59:05 +01:00
mtlcl410andClaude Opus 5.5 d6ffacbd19 Merge upstream/main into fix/update-without-prev-is-refused
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
2026-11-08 20:50:01 +08:00
mtlcl410andClaude Opus 5.5 daf98e3252 fix(edit): page_rules reads the content streams' data from ContentStream
Main merged #1977's rules.rs (which destructured content_streams as
(entry, data) tuples) after content_streams started returning
ContentStream records, so pdfcraft-edit stopped compiling.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
2026-11-08 20:37:29 +08:00
mtlcl410 ca146cd23f Merge remote-tracking branch 'upstream/main' into lane1-6501 2026-11-08 20:31:22 +08:00
FredApps 82c2009d09 Merge pull request #6208 from vangel76/fix/5939-sign-need-appearances
Signing a form that sets NeedAppearances no longer makes Acrobat ignore the signature
2026-11-08 13:31:20 +01:00
FredApps 5e0619d7eb Merge pull request #1977 from vangel76/feat/redact-mark-regex
Redact: mark text by caller-supplied regex (#1886)
2026-11-08 13:30:34 +01:00
FredApps 6fa72b914c Merge pull request #4876 from vangel76/perf/write-full-retain-parsed-objects
perf(cos): write_full keeps the objects it parsed while numbering
2026-11-08 13:22:45 +01:00
FredApps efe75d3a30 Merge pull request #4874 from vangel76/perf/cos-reconstruct-4868
perf(cos): speed up byte searches during cross-reference reconstruction
2026-11-08 13:22:36 +01:00
FredApps 3ba5b28533 Merge pull request #1983 from vangel76/feat/optimize-target-bytes
Optimize: optional target_bytes for doc_optimize (#1889)
2026-11-08 13:22:27 +01:00
FredApps 3bfbe24d7b Merge pull request #1988 from vangel76/fix/min-window-width
UI: allow a half-screen window, and fold the mode bar when narrow (#1913)
2026-11-08 13:22:15 +01:00
mtlcl410 67ac32a2a1 Merge remote-tracking branch 'upstream/main' into lane1-6501
# Conflicts:
#	crates/filters/src/lib.rs
2026-11-08 20:21:16 +08:00
FredApps ed71db7c0f Merge pull request #4878 from vangel76/perf/cos-serialize-fmt-4870
perf(cos): write hex strings, integers and references without the formatter
2026-11-08 13:19:42 +01:00
FredApps 04f3421c9f Merge pull request #5562 from vangel76/fix/bookmark-rename-select-5529
Select the bookmark title when creating or renaming a bookmark (#5529)
2026-11-08 13:19:34 +01:00
FredApps 7d02602bde Merge pull request #5564 from vangel76/feat/crop-toolbar-5330
Add Crop pages to the document quick toolbar (#5330)
2026-11-08 13:19:28 +01:00
FredApps ca888de41f Merge pull request #6067 from vangel76/contributors-vangel76
contributors: set names for vangel76
2026-11-08 13:19:21 +01:00
FredApps 0a7798707b Merge pull request #5825 from Piohrun/fix/flate-input-work
fix(filters): inflate with zlib-rs everywhere, and charge the image allowance for what Flate reads
2026-11-08 13:11:25 +01:00
FredApps 8287ad0d06 Merge pull request #6289 from Piohrun/fix/partial-content-rewrite
M2.6: never rewrite a content stream from the part before its damage
2026-11-08 13:10:56 +01:00
NetterSilver f750589812 Keep ruled tables when exporting a PDF to Word (#5154)
Fixes #5149
2026-11-08 19:28:07 +08:00
Zhihui Song 3763f120a3 chore(print): align application lockfile with refreshed Windows loader 2026-11-08 19:07:54 +08:00
mtlcl410andClaude Opus 5.5 52afba1ad0 M1: the cut-off update tests check the model's first page is the update's 300 x 150 page (core.repair-broken-files)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
2026-11-08 16:49:03 +08:00
mtlcl410andClaude Opus 5.5 9b470180ab M1: the delimiter test rewrites only the cut-off update, and a comment after obj is tested to end the keyword (core.repair-broken-files)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
2026-11-08 16:29:58 +08:00
mtlcl410andClaude Opus 5.5 577842d494 M1: an object header needs an object number that fits 32 bits, and the trailing-data test names where renderer and model differ (core.repair-broken-files)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
2026-11-08 14:50:25 +08:00
mtlcl410andClaude Opus 5.5 0b0219d966 M1: an object header needs a token boundary after obj, as the document model reads one (core.repair-broken-files)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
2026-11-08 14:33:28 +08:00
mtlcl410andClaude Opus 5.5 66763378aa M1: a rebuild whose trailer lacks the encryption dictionary is not taken, tested (core.repair-broken-files)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
2026-11-08 14:12:50 +08:00
mtlcl410andClaude Opus 5.5 49ec643a78 M2: a page's own /MediaBox wins and a nearest box without area gives Letter, tested in the renderer and model (view.render-pages)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
2026-11-08 14:03:32 +08:00
mtlcl410andClaude Opus 5.5 d65d40a5bf M2: a page takes its nearest ancestor's /MediaBox and keeps its origin, tested (view.render-pages)
Tests only: an intermediate /Pages node's box wins over the root's, and content is placed by a
box whose origin isn't 0 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
2026-11-08 13:15:05 +08:00
mtlcl410andClaude Opus 5.5 4a2507c086 M1: a cut-off update is rebuilt only after the named table refused a wrong password and only when encrypted as that table is; trailing object text is tested to read as the model reads it (core.repair-broken-files)
- Pdf::new_with_password reads the table the last startxref names first: a wrong password is
  refused through it, and the rebuilt table is taken only when it is encrypted exactly when
  that table is.
- Tests: an encrypted file with a cut-off update needs its password; data after %%EOF holding
  an object header reads as the document model reads it (both take its page).
- vendor/README.md lists the split tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
2026-11-08 12:47:14 +08:00
mtlcl410andClaude Opus 5.5 5204abbb08 M2: a page inherits a grandparent's /MediaBox, origin kept, tested (view.render-pages)
Tests only: a /MediaBox two /Pages levels up, with its origin away from 0 0, gives the page its
crop, size and view matrix, and the renderer sizes such a page at that box.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
2026-11-08 12:37:57 +08:00
vangel76andClaude Opus 5.5 dcad5ff3b3 fix(sign): zero-filled placeholders are unsigned; look inside appearance XObjects (#5939)
- `has_signatures` treats a /Contents of only zero bytes as unsigned and finds
  signature dictionaries in one pass over the file (field /V values, plus
  /ByteRange dictionaries and document timestamps) instead of two.
- Before the first signature, a field's own appearance counts as drawing text
  only if it or a form XObject it paints shows text; a background-only XObject
  no longer keeps an appearance that would leave the field blank. The look
  inside opens at most 16 streams; past that it counts as text, as before.
- Tests: zero-filled placeholders (hex and literal), document timestamps, a
  widget without /AP, background-only and text-drawing XObject appearances
  with an unencodable character.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 05:31:05 +01:00
mtlcl410andClaude Opus 5.5 650b46861e M1: the read-as-before cases are three tests, and trailing data checks the model too (core.repair-broken-files)
Tests only: a complete update, trailing data without objects and a short cut-off update each
have their own test, and the trailing-data case asserts the model's page count as well.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
2026-11-08 12:06:38 +08:00
mtlcl410andClaude Opus 5.5 ee1b5454ee M2: a page without its own /MediaBox inherits its parent's before the US Letter fallback, tested (view.render-pages)
Tests only: the page model and the renderer size a page whose /Pages parent carries the
/MediaBox (ISO 32000-2 §7.7.3.4) at that box, 300 x 400, not US Letter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
2026-11-08 12:02:11 +08:00
bmh129 44d7fb996a M10: name the web OCR pool's run router runs (ocr.ocr-web)
page_modules_read_the_pointer_only_through_page_pointer treats any file
that mentions `.router.` as a page module, and failed on
workflows/ocr_web.rs: its `self.router` is the OCR pool's
ocr_route::Router, which hands each page's text to the run that sent it,
not the pages' PageRouter. Adding the file to PAGE_MODULES would put
the workers under the page-input checks, so the field is renamed
`runs` instead.

Tests: the page_pointer tests and all 808 pdfcraft-ui-egui lib tests
pass, and cargo check for wasm32-unknown-unknown builds.
2026-11-07 21:35:59 -06:00
bmh129 4bcc63e059 M10: the Verify screen downloads the web OCR models itself (ocr.ocr-web)
In the web build, Verify's Run OCR and its page/region re-reads never
started the model download. On a fresh page they failed at once with the
desktop's "set PDFCRAFT_MODELS" message, and worked only after Recognize
Text had downloaded the models.

Both now start the download (web_models_missing), say "Downloading the
text recognition models…" and remember what was asked; poll_models runs
it once the models land, or shows "Couldn't download the text
recognition models: {e}" when the download fails. Nothing runs if the
screen was closed meanwhile, and an engine the browser can never run
says why instead of waiting.

Tests: models_landed starts a waiting run and a waiting re-read, reports
a failed download without touching the review, and runs nothing for a
closed screen. The first three fail without the fix. Checked by hand in
Chrome: a fresh page, Verify > Run OCR downloads the models and reads
the page (47 words on a real scan); with the models missing it shows
the HTTP 404 and a second click after restoring them works.
2026-11-07 21:35:59 -06:00
bmh129 ce25eb2aef M10: web OCR docs, parity and roadmap after the port onto #977 (ocr.ocr-web)
Hosting notes for the models and workers, the platform parity text, the
ocr.ocr-web parity entry (now citing the ported tests, with the known
limits: the page runs the cleaning steps, the Verify screen re-reads on
the page, ocrs only), and the roadmap logs.
2026-11-07 21:35:59 -06:00