Commit Graph
4320 Commits
Author SHA1 Message Date
Nick Nyssen 1688bd407a M14: check the Arial last resort only where it is installed
CodeRabbit caught that the macOS oracle asserted unconditionally that
/Library/Fonts/Arial Unicode.ttf resolves and loads under MAX_BYTES. On a Mac
without that font the assertion fails while Devanagari coverage is perfectly
fine — the loader treats candidates as optional, and so should this test.

Hardened beyond an is_file() guard: is_file() follows symlinks, so a link
whose target Apple has moved would read as "not installed" and skip — the very
dead-path defect this branch exists to catch. Gate on symlink_metadata so a
present-but-unresolved entry fails loudly, keep the resolution and MAX_BYTES
assertions where the face exists, report otherwise. The path is taken from the
list instead of repeated here, so it cannot drift from what ships.

Also pin three load-bearing constants in the CI-visible list test, because each
could otherwise be retuned silently (verified: all three were green before):
MAX_BYTES 32 MiB — the cap that decides whether a 23 MB Unicode face is
accepted, raised or lowered both now fail; DEVANAGARI_PROBE U+0915 — what makes
a Hindi check a Hindi check, since Arial covers both scripts and was masking a
probe swap; MAX_FACES 16 — the depth into .ttc collections the loader trusts.

Verified on macOS 26.6 (Apple M5 Max): cargo fmt --all clean; clippy
--all-targets -D warnings quiet; system_fonts 12 passed in normal mode and under
PDFCRAFT_SYSTEM_FONTS=0; whole crate 1340 passed / 0 failed. Mutations: cap
lowered (2 tests red), cap raised to 512 MiB, probe swapped to Arabic alef and
MAX_FACES cut to 1 all red via the pins. One limit stays open, stated rather
than glossed: nothing verifies 16 faces is deep enough for real collections —
that needs a synthetic .ttc with the covering glyph past index 16, and here every
needed face sits at index 0.
2026-10-19 23:56:36 -07:00
Fernando AreánandClaude Opus 5 4ac7004292 M14: Spanish catalog covers the bundled key union
es.tsv was missing 143 of the 2,674 (context, English) keys the other
bundled catalogs carry, so those strings fell back to English inside an
otherwise Spanish interface: every calendar month and weekday, the whole
certificate context of the signature inspector, the X.509 key usages, the
signature-revision and digital-ID lines, password validation, eight plural
messages, the combine-from-folder strings, the rendering and stale-file
notices and the tooltips that spell their shortcut out.

Spanish now covers the whole union, as lt and vi do: 2,531 -> 2,674 of
2,674, measured as docs/localization-parity.md describes. Counts there and
in ROADMAP.md re-measured against the current union; vi is restated at
2,674 for the same reason, still 100%.

Translations reuse the vocabulary already in the file (ID digital, Acercar
/ alejar, Portapapeles, A doble cara, Cortar y apilar) and were written
from the English labels, not from another implementation.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-20 08:20:16 +02:00
SBaksa daa76197dc Select All takes the whole document's text while scrolling continuously (#2639)
Scrolling continuously, Edit > Select All (Cmd+A) selects the text of
every page of the document; one page at a time it still selects the page
shown, as does a document of one page. Shown pages highlight as their
text arrives, and Copy gets all of it in page order, reading the text of
pages not read for display (text far away is let go to bound memory, so
it isn't kept for this). A press on a page or Escape ends it. Select All
still returns whether text is selected.

The Select All parity entry covers both modes; the viewer and copy
security tests run one page at a time, which is what they check.
2026-10-20 16:44:29 +11:00
PerchAnton e3bf3afa81 M12: refresh XFA fix with current feature evidence (#2615) 2026-10-20 08:33:36 +03:00
PerchAnton 5ae7e5d1ca M12: refresh XFA fix with current feature evidence (#2619) 2026-10-20 08:30:32 +03:00
PerchAnton 5a49f7b626 M12: refresh XFA fix with current feature evidence (#2624) 2026-10-20 08:27:14 +03:00
PerchAnton 01dc4ac90f M12: refresh XFA fix with current feature evidence (#2648) 2026-10-20 08:23:25 +03:00
Nick Nyssen 21dc64ea5f M14: skip the loader tests when installed faces are switched off
`a_script_fallback_is_the_first_candidate_with_the_probe` calls
script_fallback, which returns nothing when PDFCRAFT_SYSTEM_FONTS=0 — the
switch cargo xtask screenshots sets (AGENTS.md §1.4) — so it failed in that
mode on main, independently of the Devanagari fix. Skip both loader tests with
a printed reason instead, matching crates/ui-egui/tests/fonts.rs.

Split out from the previous commit so it can be dropped without touching the fix:
PDFCRAFT_SYSTEM_FONTS=0 cargo test -p pdfcraft-ui-egui --lib system_fonts now
reports 12 passed rather than one failure.
2026-10-19 22:13:38 -07:00
Nick Nyssen 19c3c8b129 M14: find Apple's Devanagari faces in the folders current macOS uses
Two of the five paths in the macOS Devanagari list do not exist —
`Supplemental/DevanagariSangamMN.ttc`, where Apple spells the family
`Devanagari Sangam MN.ttc` with spaces as this file already does for its
Telugu and Tamil siblings, and `Supplemental/Kohinoor.ttc`, one level above
where Kohinoor.ttc actually lives — so the family documented as second choice
has never been reachable. Both arrived together in #1033 and are present from
v0.7.1 through main; no CI could notice, since ci.yml has no macOS runner and
read() logs only on a hit.

List the families best-first, correctly spelled, and look each up in both
macOS system font folders. Preference is unchanged: all of Devanagari MT's
folders are tried before Sangam MN starts, Arial Unicode stays last, and at
most one installed face per script is still loaded (§1.4).

Devanagari MT wins on the machine tested, so Hindi renders identically here;
the change is that a Mac without it lands on the intended fallback instead of
skipping past it. That missing-Mac case is read off the code path, not
observed — no screenshot or log claims otherwise.

Tests: an exact assertion of the whole list (spellings, folders, order) that
runs on every OS and also pins devanagari_candidates() to it; a loader test
proving the first readable candidate wins, using two bundled faces of
different byte length; a spaced-name resolution test against a temp
macOS-shaped tree that panics rather than passing silently when the temp dir
is unusable; and a macOS-only disk oracle requiring every family folder that
exists here to be reachable, the list to cover Devanagari, Arial Unicode to
load under MAX_BYTES, and devanagari_fallback() to land on the same bytes and
face as this list. Families Apple stops shipping are reported, not failed —
that absence is what the list exists for.

Verified on macOS 26.6 (Apple M5 Max): fmt --all clean; clippy --all-targets
-D warnings quiet; system_fonts 12 passed; whole crate 1340 passed / 0 failed;
xtask layers (37 crates) and assets (272/6/22). Eight of ten deliberate
breakages turn a test red; MAX_FACES depth and the PDFCRAFT_SYSTEM_FONTS=0
guarantee do not, both disclosed rather than left implicit.
2026-10-19 22:13:15 -07:00
Hazel Granados e9c53ea718 M7: keep a behind watermark under one on top on an empty page (#3591)
On a page with no content of its own, an on-top watermark is the first
stream in /Contents, so it was counted with the behind-content marks and
a watermark added behind later was drawn over it. Nothing records
whether a watermark is behind, so a new behind mark now goes right after
the last background, which is always below any on-top watermark. A newer
behind watermark goes under older ones again, as before #3591.
2026-10-20 00:09:41 -05:00
jpeskovandClaude 2a3dc47291 fix(print): restore previous paper size after leaving Label mode (#3564)
Choosing Label under Page Sizing & Handling swaps the paper to the
4 x 6 in label stock. Leaving Label for Size, Poster, Multiple or
Booklet now gives back the paper chosen before, unless another paper
was picked while in Label.

Fixes #3564.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-20 10:31:56 +05:30
Hazel Granados 5beaf88a2a M7: paint a new background over older ones (#3591)
Marks behind the page content were all inserted at the start of
/Contents, so a second background went under the first and the old
colour stayed. Backgrounds now come first, then behind-content
watermarks, each in the order added. A watermark added after a
background no longer disappears under it.
2026-10-19 23:42:25 -05:00
Eric Kaden 56b316a7f4 Forms: a radio group's read-only button can't be chosen by a click 2026-10-20 00:35:54 -04:00
Osvaldo Duran MelendezandClaude Sonnet 5.5 83227d343a Format with rustfmt
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 00:22:45 -04:00
Eric Kaden 0a77db066c Forms: a radio group's read-only button is left unhighlighted on its own 2026-10-20 00:20:02 -04:00
hcchung1andClaude Sonnet 5.5 acacf9485f fix(automation): hide_text_block resolves its number like text_edit, and a merged paragraph is not followed (#2516)
page_render's hide_text_block used the paragraph number as a position in the page's current
paragraphs, so after an edit regrouped the page it hid a different paragraph from the one
text_edit would rewrite. It now resolves the number against the text_paragraphs listing and is
refused when the paragraph is gone.

text_edit also accepted any overlapping paragraph that contained the requested text as the
edited one. When the edit merged the paragraph into a neighbour, the merged paragraph contains
that text too, so the number followed it and a second edit by that number dropped the
neighbour's text. The edited paragraph must now show exactly the requested text; a merged one
leaves the number stale.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 11:57:48 +08:00
Eric Kaden a3b942021f M12: doc comments, and words keeps its own 2026-10-19 23:46:56 -04:00
Eric Kaden 5cd7e816b9 M12: doc comments for the functions this change touches 2026-10-19 23:46:16 -04:00
Eric Kaden 24b55275a5 M12: doc comments for the functions this change touches 2026-10-19 23:46:14 -04:00
Eric Kaden a0ae8a3996 M6: doc comments for the functions this change touches 2026-10-19 23:43:02 -04:00
Eric Kaden 032febca2f M6: doc comments for the functions this change touches 2026-10-19 23:42:56 -04:00
Eric Kaden 77eb328c83 Forms: doc comments for the functions this change touches 2026-10-19 23:42:37 -04:00
Eric Kaden 15ab8c7a2c M12: doc comments for the functions this change touches 2026-10-19 23:42:22 -04:00
Eric Kaden 465bd0a717 M5: doc comments for the functions this change touches 2026-10-19 23:41:47 -04:00
jonathanwxh-cell 4ff9bd6634 fix(render): cover all color spaces, padding and align /L policy with content crate (#3107) 2026-10-20 11:15:45 +08:00
jonathanwxh-cell d03dbd742e Merge remote-tracking branch 'upstream/main' into fix/inline-image-ei-in-samples 2026-10-20 10:54:57 +08:00
jonathanwxh-cell 1c7ad8e465 fix: merge current main into optimizer compatibility branch 2026-10-20 10:52:38 +08:00
Eric Kaden c90afe54cf M6: say why a form's Save opens Save As 2026-10-19 22:22:03 -04:00
Brandon ThomasandClaude Opus 5.5 6fb6b7cf6f Release 0.10.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 22:21:10 -04:00
Eric Kaden 0d0cce1bb0 Forms: Highlight fields marks only the fields that can be filled 2026-10-19 22:19:30 -04:00
djmushin 39d0b953ca M6: treat imported MaxLen zero as unlimited 2026-10-19 22:03:50 -04:00
djmushin 0ba01a0557 M6: optimize AcroForm JavaScript snapshots and diffs 2026-10-19 22:03:49 -04:00
hcchung1 570e6c0564 fix(automation): an emptied paragraph does not pass its number to an overlapping neighbour (#2516) 2026-10-20 10:02:06 +08:00
hcchung1 3909bebeec M7: a paragraph number keeps naming the paragraph text_paragraphs listed (#2516)
Paragraph numbers are positions in a list regrouped from geometry after
every edit, so an edit that merged a paragraph into its neighbour made the
next edit by number rewrite another paragraph and lose its text.

After text_paragraphs, text_edit and text_edit_layout find the listed
paragraph again by its text and box, and refuse one that no longer exists on
its own (list the page again). An edit's result names the numbers that are
gone in stale_paragraphs. The inline editor's switch-paragraph click holds
the same key instead of an index. Without a listing a number is a position,
as before. An identity that survives save and reopen is still #2508.
2026-10-20 10:02:06 +08:00
Eric Kaden 9366af3bad M6: side panels have fixed automation ids, and the parity note says where Print works 2026-10-19 22:01:10 -04:00
Eric Kaden 35e04743d0 M12: showing an XFA subform leaves its unnamed hidden objects hidden 2026-10-19 21:27:47 -04:00
Osvaldo Duran MelendezandClaude Sonnet 5.5 61ccfa237b Attachments: keep the bookmark rows doc comment on its function
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-19 21:08:24 -04:00
Osvaldo Duran MelendezandClaude Sonnet 5.5 39a9a6d2ca Attachments: report the added file's own key; drop an emptied indirect /Names
attachment_add compared every attachment name, including files attached to pages as comments, so a page comment with the same file name made the reported key empty. It now compares only the document-level name-tree keys. Deleting the last document attachment when the catalog's /Names is an indirect dictionary left an empty /Names behind; it is now removed from the catalog, as the direct case already did.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-19 21:08:21 -04:00
Eric Kaden 74326b455c M6: a field's own script may not open Save As 2026-10-19 21:02:37 -04:00
Eric Kaden e8eb840ec5 M6: form buttons show the side panels (execMenuItem ShowHide…) 2026-10-19 20:59:14 -04:00
Tiago KielandClaude Opus 5.5 3b6d344eb5 fix(render): find comma-below letters by character (refs #1666)
A font naming a Latvian comma-below letter by its code point (/uni0136) or by
the glyph list's name for it (/Kcedilla, /Gcedilla...) still drew nothing:
the name resolves to the cedilla name the glyph list prefers, which the
composite table does not hold. The thirteen comma-below letters are now
looked up by character, which also replaces the special case for U+021A and
U+021B. T and t with a cedilla (U+0162, U+0163) are not in that table and
keep their cedilla.

Raised by CodeRabbit on the PR.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 20:51:29 -04:00
jonathanwxh-cell a10c0d8937 Merge branch 'upstream/main' into fix/typed-signature-winding 2026-10-20 08:15:30 +08:00
MichaelandClaude Sonnet 5 1ce4965c27 fix: read the last array of a surplus-operand TJ, not the first (#3569)
`[(FIRSTARR)] [(LASTARR)] TJ` is malformed (TJ takes one array
operand), but the operator still shows the one immediately before it,
as the renderer, MuPDF and pdftotext agree. Three readers here counted
operands from the front instead and showed the discarded first array:

- crates/edit/src/text.rs (text_lines/text_paragraphs, and the Office
  export through reading_lines)
- crates/redact/src/interp.rs (search-based redaction's content
  interpreter)
- crates/a11y/src/headings.rs (autotagged heading detection)

So the editor could offer a word the page never draws, a redaction
search could miss it, and a heading could read as text nobody sees.
Take the last array for TJ in all three, matching the `_ =>
op.operands.last()` arm already used for Tj/'/" alongside it.

Added a regression test per crate (`a_tj_with_a_surplus_array_reads_
the_last_one`, `a_tj_surplus_arrays_undrawn_glyphs_are_not_seen_
under_a_mark`, `a_heading_with_a_tj_surplus_array_reads_the_one_the_
page_draws`), confirmed each fails without its fix and passes with it.
cargo test -p pdfcraft-edit (196 passed) -p pdfcraft-redact (81
passed) -p pdfcraft-a11y (44 passed), fmt, clippy -D warnings, xtask
layers and xtask assets all clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-20 08:09:59 +08:00
ffishmanandClaude Opus 5.5 0a56784df8 M9: read .p7b/.p7c certificate bundles for trust import
load_certificates now reads PKCS #7 certificate bundles (degenerate
SignedData, RFC 5652 §5.2) in DER and as PEM PKCS7/CMS blocks, the way
Windows, Acrobat and certificate authorities export chains. PEM END
lines must match their BEGIN label.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-19 20:32:37 -03:00
Tiago KielandClaude Opus 5.5 8708cbb93d style(render): rustfmt the comma-below test (refs #1666)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 19:25:14 -04:00
Tiago KielandClaude Opus 5.5 88735a7003 fix(render): draw comma-below letters in non-embedded standard fonts (refs #1666)
The stand-ins for the standard fonts (PDFium's Foxit fonts) have neither the
comma-below letters nor a commaaccent glyph, and the composite-letter patch
left comma accents out. A non-embedded font naming /scommaaccent therefore
drew nothing, which is the blank "si" left in Romanian XFA forms, and
/tcommaaccent drew a cedilla through the glyph list's alias to U+0163.

Romanian s/S/t/T and Latvian k/K/l/L/n/N/r/R/G with a comma below are now
built from the letter and the font's comma, scaled to three quarters and set
just under the baseline, moved back along the slant in italics. The uni021A and
uni021B names of T and t with a comma below, which the glyph list
does not name, resolve by code point. Lowercase g with its turned comma above
is still not built.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 19:25:14 -04:00
vangel76 7504799e05 M6: align secured-form highlight tests after rebase (#2273) 2026-10-20 01:11:01 +02:00
vangel76andClaude Sonnet 5.5 f295be1e05 Tests: field highlights are on by default, so the toggle reads "Hide field highlights" (#2273)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 01:10:07 +02:00
vangel76andClaude Sonnet 5.5 280f2439ec Preferences: field highlights on by default, with a toggle in Appearance (#2273)
New settings start with Highlight fields on. A stored choice is kept; a missing or
malformed value falls back to on. Preferences > Appearance gets the checkbox.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 01:10:07 +02:00
Eduardo Soares b175965766 Parity: limit the drop focus claim to path-bearing drops (#1620)
Byte-only drops (no filesystem path) have nothing for tab_showing to
match and open another tab, pinned by
opening_documents_without_a_path_still_open_twice; the drag-drop-open
note claimed focus for "a dropped document that is already open"
without that limit.
2026-10-19 19:21:59 -03:00