Commit Graph
3518 Commits
Author SHA1 Message Date
NetterSilverandClaude Haiku 5.5 bafb948226 Round FormCalc Str and Format exact ties away from zero
Found while testing crates/js/src/formcalc.rs:2169 (Str) and :2258 (Format number picture)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 22:19:58 +02:00
Mex f1177bb287 M6: refresh XML whitespace fix and record parity evidence 2026-10-15 22:01:42 +02:00
Tanish MankuandClaude Opus 5 13e3154ab3 fix(fonts): read the Annex D.2 alias codes as the ink they draw
#2305 fixed WinAnsi 0xAD in `crates/fonts`, and closed with two loose ends it named: the
user-visible extraction path goes through hayro, not that table, so it still reported the
invisible character; and the same Annex D.2 note makes 0xA0 the `space` glyph. This finishes
both, and makes the two tables in the product agree about the same byte.

WinAnsiEncoding gives codes 0xA0 and 0xAD the glyph names `space` and `hyphen` -- the names it
also gives 0x20 and 0x2D -- and MacRomanEncoding gives 0xCA `space`. The tables called them
`nbspace` and `sfthyphen`, whose Adobe Glyph List values U+00A0 and U+00AD are invisible
formatting characters, so extraction hid ink the reader can see: "well-known" drawn with the
0xAD byte matched no search and no redaction pattern, and a non-breaking space did not match the
space a reader typed.

Evidence. Two sources transcribe the table the same way (an Annex D implementation's docs, and
the WinAnsi.enc encoding vector R ships, which gives `/space` at octal 240 and `/hyphen` at
255), and a black-box check settles the rest: on a synthetic fixture pdftotext reads the
base-encoded codes as `a-b a b`, and keeps U+00AD for a code an explicit `/Differences` names
`sfthyphen`. We now do both. Over the 989-file pdf.js corpus the soft hyphens we extract fall
from 117 to 13 and the non-breaking spaces from 30 to 26; everything left comes from `/ToUnicode`
maps, which say what they mean and are not touched.

Scope. The base table only, in the text direction only.

- A `/Differences` entry naming `sfthyphen` or `nbspace` is a deliberate statement about one
  code and keeps its glyph list value, as pdftotext does.
- Glyph lookup is untouched, so a font program's own `sfthyphen` program is still found first.
  In hayro that is why the alias sits in the Unicode path rather than in the generated encoding
  table: `code_to_ps_name` is shared with lookup.
- Writing is unaffected: `encode` takes the lowest code showing a character, so ' ' and '-'
  still write 0x20 and 0x2D, and a caller holding a literal U+00A0 still writes 0xA0.

Tests. `fonts` pins both tables and the whole decode/encode path including the `/Differences`
case; `render` pins the extraction a reader actually gets, over WinAnsi, MacRoman and
`/Differences`. Each was watched failing with each cell and each match arm reverted in turn, so
no assertion is passing by accident. fonts 70, render 296+4, redact 49, a11y 43 and edit 156 are
green, with fmt, clippy, `xtask layers` (37 crates) and `xtask assets` clean.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-10-15 12:52:53 -07:00
Mex 87e69d2c72 M4: merge current upstream into indirect rotation fix 2026-10-15 21:48:28 +02:00
Mex 7bb2d49467 M1: merge current upstream into Flate fallback fix 2026-10-15 21:40:21 +02:00
PerchAnton ff62683ff8 M12: skip PDF container scripts during active XFA layout (#2589) 2026-10-15 22:18:58 +03:00
Dimitar KlaturovandClaude Opus 5.5 a9320efd7a Print ▸ Properties…: the driver's options in the UI language
CUPS drivers ship their names in other languages as PPD localization lines
(`*cupsLanguages`, `*de.Translation KMDuplex/Druckart: ""`, `*de.KMDuplex
Double/2-seitig: ""`), which the system print dialog uses. PdfCraft showed the
PPD's default (English) names in every language. `spool::printer_options_in`
now applies the lines for the UI language (`pt-br` → `pt_BR`, then `pt`;
`zh-hans` → `zh_CN`) to option, group and choice names. Each line is decoded as
UTF-8 on its own, as drivers write them in otherwise Latin-1 files; missing or
empty translations keep the driver's name. `printer_options` (automation) is
unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 22:13:51 +03:00
alehelandClaude Opus 5.5 fb10540990 fix(ui): dialog buttons hug their content; no page cursors under modals
The shared dialog footer laid its buttons out right-to-left in all the
height left, centred. After a taller Document Properties tab the modal
kept that tab's height, so Close floated far below a shorter tab's last
row. The footer is now one row high.

Page hovers (form fields, comments, the link tool, image editing) set the
cursor from the raw pointer position, so a hand or text cursor showed
over fields under a dialog's backdrop, where nothing takes clicks. While
a modal is open the cursor starts from the arrow each frame and only the
modal's own widgets change it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 20:59:29 +02:00
alehelandClaude Opus 5.5 d48ce4ae1b fix(ui): Document Properties gains a Space Audit tab
Properties ▸ Space Audit shows the same bytes-by-kind table as the PDF
Optimizer's Audit Space Usage, which now shares its table code. The
audit walks the whole file, so it runs when the tab opens and again only
after an edit (keyed on the document and its edit generation). The tab
is also reachable as `--dialog space-audit`.

The audit table no longer overflows its dialog: egui's default minimum
column width stretched the narrow Bytes column past the computed widths,
widening the card by about 5 points.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 20:59:29 +02:00
alehelandClaude Opus 5.5 b349ef480f fix(ui): Document Properties values line up and long fields wrap
The Description tab's plain values (File, Application, PDF producer) now
start where the text inside the Title/Author fields does, the fields use
the dialog's full width instead of a fixed 420 points, and Subject and
Keywords wrap onto more lines instead of clipping mid-word.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 20:59:29 +02:00
outragedevs 4a991b03b5 M7: Let the page range select page 1 alone
Seitenbereich „1 bis 1“ springt nicht mehr auf die letzte Seite zurück.
2026-10-15 20:21:57 +02:00
Mateus BessaandClaude Opus 5.5 64ab6b67ec fix(ui): Copy in the selection action bar closes the bar
The bar beside selected text closed after Highlight, Underline, Strikethrough,
Add comment and Replace text because those consume the selection. Copy kept the
selection, so the bar stayed open. Remember the copied selection and hide the
bar until the selection changes; the words stay selected for ⌘C or another
action.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 15:14:30 -03:00
FredApps 1d5c20c5c4 Support typed font sizes and Fill and Sign text colours (#2444, #2496) 2026-10-15 20:02:36 +02:00
mtlcl410andClaude Opus 5.5 294fea2fb8 fix(ui): Reveal in File Explorer selects files whose path has a space (#2579)
Explorer reads /select,"<path>". The path went in as one ordinary
argument, which Rust quotes whole when it contains a space
("/select,C:\a b.pdf"), and Explorer answers that by opening Documents.
A file saved to a folder or name with a space (often after Save As) was
therefore never shown. reveal_command now quotes the path after the
comma and the Windows runner passes the arguments as written; a path
containing a quote, which Windows doesn't allow, is refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz
2026-10-16 01:34:32 +08:00
PerchAnton 97d286b2b9 M12: reflow growable XFA text after form edits (#2569) 2026-10-15 20:33:03 +03:00
fanyzp 1c3cb9d14d feat(forms): nudge the selected field with the arrow keys in Prepare a form (#2608) 2026-10-16 01:15:06 +08:00
PerchAnton f06bebd520 M12: dispatch repeated XFA print buttons by their own field (#2572) 2026-10-15 20:08:05 +03:00
PerchAnton a146648648 M12: enforce XFA rich-text maxLength (#2570) 2026-10-15 19:52:42 +03:00
fanyzp 963609d7d6 fix(edit): draw the Cyrillic the Japanese faces lack with the bundled Inter face (#2593) 2026-10-16 00:31:49 +08:00
alehelandClaude Opus 5.5 b9e1b06b94 M3: name the All tools expand and collapse buttons for what they do
The sidebar's expand button was labelled "Expand", the same as the Combine
grid's per-file Expand on its hover bar. With both on screen, the Combine
grid tests' lookup by that label found two buttons and 13 of them failed.
The buttons are now "Expand all tools" and "Collapse all tools", translated
in all 22 catalogues, and the labels are tl! literals the coverage scan sees.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 17:58:11 +02:00
Krzysztof Cieślik 7e68ef44d5 fix(combine): let the cards zoom to 500% (#2531)
The Combine grid stopped at 200%, too small to read a value off an invoice
while reordering the pages of a statement. The main viewer already reached
6400%, so only the card grid was capped.

- The range is 60–500%, and the buttons and keys step
  60/80/100/125/150/175/200/250/300/400/500%.
- MAX_SIDE, the thumbnail texture cap, goes 768 → 1536, so a card near the top
  re-renders sharper instead of upscaling a 768px texture. It only binds near the
  top: a card below it asks for less and costs no more than it did. Up there one
  thumbnail is a few megabytes, so TEXTURE_BUDGET and UPLOAD_BYTES_PER_FRAME keep
  the cache at a screenful plus one frame's uploads — and a screenful at the top
  of the range is a card or two, because a card is wider than most windows.
- The control channel's range message is derived from the constant rather than
  repeating "60 and 200", so it cannot drift from the range again.
2026-10-15 17:43:46 +02:00
NetterSilverandClaude Haiku 5.5 db4157099a Don't treat a date ending in "Sep" as PM in AFDate/AFTime parsing
Found while testing crates/forms/src/af.rs:590

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 15:43:14 +00:00
NetterSilverandClaude Haiku 5.5 7cc073ab89 Shorten over-long part file names in doc_split by bookmarks
Found while testing crates/automation/src/lib.rs:1747

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 17:42:18 +02:00
Codex b05a06e8e2 Merge main CI repairs and preserve button export translations 2026-10-15 17:29:00 +02:00
Verix bdb943dc3d M3: a page jumped to in single-page view no longer hops into place
The jump scrolls to MARGIN - GAP above the page. A page that fits has
nothing to scroll, and egui clamps the offset only after drawing the
frame, so the page showed 14 pt too high for a frame and then hopped
down. Clamp the jump to the scroll range before handing it to egui.
2026-10-15 17:28:46 +02:00
jonathanwxh-cell 279712769d fix(edit): keep overlapping watermarks and distinct paragraphs on text edit (#1756) 2026-10-15 23:22:11 +08:00
komo1iddinandClaude Opus 5.5 8ebe4f7a76 M7: write a full font program compressed and find it again on any page
A text edit that needs glyphs the source font's embedding lacks writes
the face's full program once. It was written uncompressed, and the
document-wide search that lets another page reuse it compared the
stream's raw bytes, so it only matched an uncompressed copy.

Write the program with Flate, and compare its decoded bytes (after the
/Length1 check) both on the page and across the document.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 20:21:02 +05:00
Verix ff526a7896 M3: single-page view turns pages without a blank frame
At Fit Page in single-page view, every wheel turn forward drew one
blank frame before the new page appeared.

- Lay out the shown row again after the wheel is read. The jump to the
  new page was measured from the old row's place and scrolled both out
  of view; going back it came out negative and was clamped, so only
  forward turns flickered. The edge-turn deferral that worked around
  this goes.
- Prefetch the rows either side of the shown one, so the next page is
  rendered before the turn instead of showing blank paper.
2026-10-15 17:19:56 +02:00
Osvaldo Duran 96afca8fd2 Merge main (dc41044b) into pr/attachments: the Vietnamese and Lithuanian catalogs' new rows beside this change's 2026-10-15 11:09:41 -04:00
oracola91 00fb10cf1e fix(crypt): /Perms limits what an edited /P allows
AES-256 files (R5 and R6) store the permissions twice: in clear in /P,
and in /Perms, encrypted with the file key (ISO 32000-2, Algorithm 13).
We wrote /Perms but never read it, so a document opened with the user
password got whatever /P said, even when /P no longer matched /Perms.

permissions() now decrypts /Perms and, when it holds a valid block
(marked "adb"), counts a permission only if both /P and /Perms grant
it. Without a readable /Perms, /P applies as before. R2 to R4 need no
check: /P is part of their file key, so an edited /P does not open.
2026-10-15 17:56:45 +03:00
alehel cd16644a64 Merge remote-tracking branch 'origin/main' into feat/all-tools-expand-view
# Conflicts:
#	ATTRIBUTION.toml
#	crates/ui-egui/src/i18n/lt.tsv
#	crates/ui-egui/src/i18n/vi.tsv
2026-10-15 16:54:41 +02:00
komo1iddinandClaude Opus 5.5 398ad77077 M7: rewrap a paragraph at a slant at the width its rows have
A turned paragraph's width came from its rows' upright bounding boxes,
turned into the baseline's frame. On a slant that box is wider than the
row by the row's height times |sin 2θ| (about 12 pt for 12 pt text at
30°), so a rewrite let a word that doesn't fit stay on its row.

Each run now also records its box along and across its baseline, from
the same corners as its upright box, and a line unions those. Grouping
and the rewrite's width read that box. Upright and quarter-turned text
are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 19:51:57 +05:00
Guillem VelaandClaude Sonnet 5.5 aad803caae M14: add Catalan interface and date localization
Register Catalan (`ca`) as an interface and date language with a
2,592-entry contributor-original catalog written from the meaning of the
English labels. Plurals use the one/other rule; every `ca-*` locale,
including Valencian (`ca_ES@valencia`), resolves to this catalog.

Tests cover registration and persistence, every command, menu, tool group
and section, every `tl!` literal in the UI source, and every key in the
other bundled catalogs. The Latin-script glyph test in tests/fonts.rs now
includes Catalan (the interpunct of l·l is covered by the bundled faces).

Catalan dates elide the preposition before a vowel (7 de març, 7 d'abril,
8 d'octubre), so the date language sets months_with_day, as Czech and Russian
do; a unit test pins it.

Update localization docs, the parity table and the roadmap log, and add the
ATTRIBUTION.toml entry (ATTRIBUTION.md regenerated). The contributor, a
native Catalan speaker, has reviewed the translation.

Validation: cargo fmt --check; clippy -D warnings and tests on
pdfcraft-ui-egui (i18n, fonts); pdfcraft-engine dates tests;
cargo xtask assets; cargo xtask layers.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 16:51:02 +02:00
FredAppsandCodex dc41044ba7 Fill Vietnamese and Lithuanian catalog coverage gaps (#2510)
Co-authored-by: Codex <codex@openai.com>
2026-10-15 16:50:50 +02:00
FredAppsandCodex 609a724235 Fix main UI regressions in paging, fonts and test expectations (#2502)
* Fix main UI regressions in paging, fonts and test expectations

* Wait for asynchronous dropped-document preparation in regression

---------

Co-authored-by: Codex <codex@openai.com>
2026-10-15 16:50:45 +02:00
FredAppsandCodex 5259491cf4 Tests: update save and search regressions for current behavior (#2484)
Co-authored-by: Codex <codex@openai.com>
2026-10-15 16:50:39 +02:00
mtlcl410andClaude Opus 5.5 491ce2da5b fix(i18n): zh-hant had two keys twice after concurrent merges (#2414)
the Revert prompt to zh-hant.tsv; merged together, the catalog held both
copies and `bundled_catalogs_are_consistent` (and the tests that load
zh-hant as a reference) failed on main. Keep #1750's wording (字型大小,
「」 quotes, as the rest of the catalog) and drop the other copy.


Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 16:50:33 +02:00
wstockandClaude Fable 5.1 224416a3dd Tests: the signing test's password meets the 8-character minimum (#2417) (#2420)
signing_with_translated_labels_through_tools (from #1951) creates and uses
a digital ID with the password "secret1"; #2201 ("harden .p12 digital IDs")
now requires at least 8 characters. Each passed alone; together the test
fails on main, and so does every PR's test job. The password is "secret12"
in both places.


Claude-Session: https://claude.ai/code/session_011K1peyrh5MdZ6ttHkVq8Gh

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-15 16:50:04 +02:00
Codex 403323f425 Merge main and address button export-value review follow-up 2026-10-15 16:22:36 +02:00
Combiler01 b31e6b49db merge: reconcile upstream/main with local changes 2026-10-15 19:36:23 +05:30
oracola91 d0a3427184 fix(platform): a save keeps the permissions of the file it replaces
On Unix the staging file got the default mode for a new file (usually
0644) and was renamed over the original, so saving a private 0600 PDF
left it readable by other local users. The staging file is now created
owner-only and given the original's permissions before anything is
written. A new file still gets the usual mode. Desktop save, the CLI
and the automation tools all write through this function.

Fixes #1790.
2026-10-15 16:40:45 +03:00
Marco Arnulfo d5bde67e74 Ctrl+V doesn't paste a picture while preparing a form 2026-10-15 14:41:59 +02:00
Marco Arnulfo b248dffdff Hebrew file names: draw them with an installed Hebrew face when the build has none (part of #586) 2026-10-15 14:27:21 +02:00
Osvaldo Duran e46cc70d73 Merge main (afa8e184) into pr/attachments 2026-10-15 07:59:50 -04:00
Combiler01 6f9ec0f576 feat(ui): pinned tools section on Home 2026-10-15 17:27:45 +05:30
Marco Arnulfo 6882ce3436 Ctrl+V pastes a picture from the system clipboard onto the page (fixes #2494) 2026-10-15 13:00:32 +02:00
Codex d8e46c7b74 Merge current main into Pages sidebar select-all fix 2026-10-15 12:56:18 +02:00
komo1iddinandClaude Opus 5.5 e0ef098381 M7: drop the fallback fonts a text edit leaves unused
Each edit that draws Japanese or Hebrew characters the page's fonts lack
generates new Type 3 fonts with the outlines of every character it draws.
Editing the paragraph again generated new ones and left the old ones in
the page's resources, so every edit added a set of glyph outlines to the
file.

After replace_line and rewrite_block, the page's generated fallback fonts
(Type 3, /Name /PCJapanese or /PCHebrew) that no Tf selects any more are
removed from its own font dictionary. The content read for this is the
page's streams, every form XObject it can reach that has no resources of
its own (those use the page's, ISO 32000-1 7.8.3), and the glyph
procedures of Type 3 fonts without resources. If any of those can't be
decoded strictly, nothing is removed. Registered fonts (PCFull) and the
file's own fonts are never touched.

Tests: a page with an unused generated font, one its content selects,
one only a resource-less form selects and a file's Type 3 font that only
shares the name prefix keeps all but the first after a rewrite, and keeps
everything when such a form can't be read. Rewriting Japanese text twice
(with craft-fonts) leaves only the second rewrite's fonts. The first test
fails without this change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 15:13:34 +05:00
komo1iddinandClaude Opus 5.5 2109c6785e M7: show a shaped run in one text object instead of one per glyph
Shaped text (Arabic, Indic, combining marks) was written as one text
object per glyph: BT, the whole text state (Tf Tc Tw Tz TL Ts and the
colour), Tm, Tj and ET. A 15-glyph row took 15 text objects and 392
tokens (the whole stream), a long Arabic paragraph thousands of operators, and other
viewers saw every glyph as a separate piece of text.

Each run is now one text object: the state once, one Tm, and the glyphs
in TJ arrays. A glyph's adjustment moves it from where the glyph before
it ends (its width in the embedded font) to where shaping put it, and a
mark shaped above or below its letter is raised with Ts, then reset
(ISO 32000-1 9.4.3, 9.3.7). Character and word spacing are part of those
positions, so Tc and Tw are 0 in the run. The same row is now 1 text
object (90 tokens for the stream), and renders the same at 300 dpi (138 of 33
million bytes differ, by 1 level, from rounding).

The new test shapes marks beside and above their letters with Inter,
reads each glyph's origin back from the TJ displacements and checks it
against the shaped position. It fails without this change (15 text
objects in the run against 1).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 14:58:32 +05:00
Philip 0c06186486 Merge remote-tracking branch 'origin/main' into feat/edit-scanned-page-offers-ocr
# Conflicts:
#	ROADMAP.md
2026-10-15 10:31:33 +01:00