Commit Graph
823 Commits
Author SHA1 Message Date
Max Abramowitz 3a117c3c0e M10: open Word, Excel and PowerPoint files through LibreOffice
## What this changes

**File ▸ Open opens Word, Excel, PowerPoint, OpenDocument and RTF files** as new, unsaved PDFs (`Report.docx` → `Report.pdf`), the "LibreOffice sidecar" that `docs/gaps.md` (gap 8) and `docs/file-format-parity.md` planned for `create.from-office`.

- **Conversion** (`crates/create/src/office.rs`): an installed LibreOffice runs headless as a separate process, in a private temporary folder (the input is always `document.<ext>`, so the user's file name never reaches its command line). It gets a fresh profile with `DisableMacrosExecution`, `MacroSecurityLevel` 3 and `BlockUntrustedRefererLinks` set, and Writer's and Calc's `Content/Update/Link` set to *Never* (2 for Writer and 1 for Calc: the two number their values differently), no console window on Windows (`CREATE_NO_WINDOW`), and is killed after 120 s. The output is size-capped (512 MB), must start `%PDF-`, and must open as a PDF before it is used. LibreOffice is found through `PDFCRAFT_SOFFICE`, the `PATH`, then the usual install folders per OS. Without it, the user is told it's needed rather than "not a readable PDF".
- **Off the frame thread:** File ▸ Open converts on the existing open worker (`ResultKind::Converted`); the frame thread only opens the result.
- **Detection:** `SourceKind::Office` requires an Office extension *and* an OLE, ZIP or RTF signature, so `photos.zip`, or a PDF saved with a `.docx` name, are not misread.
- **Open dialog:** PDF (still the default), Images, Office documents, Text, All files. All files is left out on macOS, where rfd merges every filter into one allowed-types list, and on the web; Office documents are left out on the web. The extension lists are now shared constants in `pdfcraft-create` (`IMAGE_EXTENSIONS`, `TEXT_EXTENSIONS`, `OFFICE_EXTENSIONS`), used by both detection and the picker. The duplicate filter list in `open_dialog` is gone. The two new labels are in all 22 catalogues, with their `ATTRIBUTION.toml` hashes updated.
- **Automation:** `doc_create_multiple`, `doc_combine` and batch `convert` go through `convert_to_pdf`, so they take Office documents too; their descriptions say so.

**Deliberately not in this PR:** Insert pages, Combine files and Create ▸ Multiple files convert on the frame thread, so they now refuse Office documents with a pointer to File ▸ Open (`convert_to_pdf_inline` / `as_pdf_inline`) rather than freezing the window for seconds. Moving them onto a worker is the follow-up. `create.from-office` goes planned → **partial**, with that and the rest listed in its notes.

## How you verified it

On Windows 11 Pro with LibreOffice 26.8.1 installed, per crate:

- [x] `cargo fmt --check`
- [x] `cargo clippy -p pdfcraft-create -p pdfcraft-engine -p pdfcraft-ui-egui -p pdfcraft-automation -j 2 --all-targets -- -D warnings`
- [x] `cargo test -p pdfcraft-create -p pdfcraft-engine --lib` (42 and 276 pass); `-p pdfcraft-automation --test automation` (the combine/create tests); `-p pdfcraft-ui-egui --lib open_worker` and `--test editing --test create`
- [x] `cargo xtask layers`, `cargo xtask assets`, `cargo xtask parity --partial`
- [ ] wasm check: the `wasm32-unknown-unknown` target isn't installed here, so I'm leaving it to CI. The web paths are `cfg`'d and were reviewed by eye.

**Tests seen failing before the fix**, by reverting each part:
- Detection off → `office_documents_are_their_own_kind`, `source_kind_tells_pdfs_images_and_text_apart`, and both engine Office tests fail.
- Worker conversion off → `file_open_converts_an_office_document_on_the_worker` fails with the old user-facing message, *"the file is not a readable PDF: no readable page tree or cross-reference data was found"*.

New tests also cover a converter that hangs (it's stopped; the test binary stands in for LibreOffice), one that writes no PDF, a missing converter, temp-folder cleanup, `file://` URL escaping (spaces, drive letters, UTF-8), and the search order.

**Real conversions, end to end:** `crates/automation/tests/it/office.rs` builds a minimal DOCX, an XLSX (with a formula, `=6*7`), a PPTX and an RTF inside the test, so no binary fixtures are committed. It runs them through `doc_create_multiple` in `separate` mode (each output reopened and its text checked, including `42`) and in `combine` mode (page order and bookmarks), and through `doc_combine` beside a PDF, with a page range on one file. These tests, `libreoffice_converts_a_document_when_installed` and the process-tree cleanup test (5 out of 5 reruns) pass with LibreOffice 26.8.1. The Office tests skip where LibreOffice isn't installed, which includes CI.

Three existing tests used a 4-byte `report.docx` as their "file that can't be converted" example. That's no longer true, so they now use `archive.zip`, which keeps what they test.

## Never-crash

- [x] No new `unwrap`/`expect`/`panic!`/`unreachable!`/`todo!` outside tests
- [x] No input-derived indexing or slicing (`rsplit_once` for the extension); the PDF read back is size-capped
- [x] No `unsafe`. The Windows flag uses `std::os::windows::process::CommandExt`
- [x] A crashing, hanging or misbehaving LibreOffice is an error, never a panic or a stuck app: the worker's `catch_unwind`, a 120 s kill, and output checks

## Provenance

- [x] No Adobe assets; no fonts; no copied code
- [x] LibreOffice (MPL-2.0) is only *run* as an external process, as the docs planned; nothing of it is linked or copied. Its command-line options and the profile keys come from LibreOffice's public documentation.
- [x] The translations are contributor-original, written from the plain meaning of "Office documents" and "All files" ("Office" kept as a product name); hashes updated, `cargo xtask assets` passes

## Security

- [x] `--root` confinement unchanged: automation still resolves and reads paths before converting; only the private temp folder is written outside it
- [x] MCP and the control channel untouched
- [ ] **No new outbound network: please decide.** PdfCraft itself opens no connection. The profile blocks untrusted referer links and sets Writer and Calc never to update linked content on load. I converted eight synthetic files that link to a listener on 127.0.0.1: RTF `INCLUDETEXT` and `INCLUDEPICTURE`, a DOCX external picture, an ODT linked section and linked picture, an ODS table source and an external cell reference, and an ODP linked picture. None made a connection, with or without the link settings. Two things remain open: Impress has no link-update setting, and the process's network access isn't sandboxed (documented in `crates/create/README.md` and `docs/gaps.md`).

## Parity and reach

- [x] `create.from-office` planned → partial, with the evidence tests and what's still missing
- [x] Reachable headlessly (`doc_create_multiple`, `doc_combine`, batch `convert`)
- [x] Docs: `docs/file-format-parity.md` (Word/Excel/PowerPoint and RTF rows), `docs/gaps.md` gap 8, `docs/target-app-parity.md` row J (numbers not re-measured), `docs/roadmap.md` M10, the `ROADMAP.md` log, and the `crates/create` README

## Anything a reviewer should look at first

1. **The network question** above. It's the owner's call.
2. **The frame-thread restraint:** Insert, Combine and Create Multiple refuse Office documents rather than block. Is a worker for those wanted in this PR, or as a follow-up?
2026-11-11 11:06:01 +01:00
Erkan DogruandFredApps f6c59c0b93 fix: integrate persistent AcroForm script workflows with native prompts and appearance writeback (#5699)
* AcroForm: integrate persistent timesheet script workflows

* AcroForm: address review caching, worker stacks and live metadata

* M6: address second review of AcroForm script workflows

* M6: handle top-level ASI boundaries and verify cyclic calculation results

* M6: bound script workers and isolate pending completions across edits

* M6: make form resets visible before subsequent script reads

* M6: include calculated dependents in reset comparison baselines

* M6: bound reset writeback work before native completion

* M6: charge expanded reset selections and field name bytes

* M6: bound string conversion bytes and charge reset widgets

* M6: preserve unread defaults and bound prompt text conversion

* M6: bound reset calls early and preserve calculated field identity

* AcroForm: address grouped calculations, field identity and widget ownership

* AcroForm: retire field instances and address native review edge cases

* AcroForm: route comparison Save As and Print to the source document

* M6: dispatch text widget mouse-up scripts

* M6: honor fit bounds for form button icons

* AcroForm: bound calculation work and preserve reset and save integrity

* Harden AcroForm script requests and worker recovery

* Keep form callbacks and focus consistent across edits

* AcroForm: preserve reset ordering and bound edit callbacks

* Fix reset appearance ordering and XFA focus after row removal

* Keep XFA focus indexes and stopped reset appearances consistent

* Document form script execution and reset helpers

* Keep script workers bounded and reject partial callback edits

* Keep form events available after a document script reaches VM limits

* Keep main's first-value Simple calculation and restore the calculateNow helper test

AFSimple_Calculate (JavaScript) and the native Simple calculation count each field's first
value again, as #5304 landed them; summing every selection of a multiple-selection list is
a separate behaviour change. Restores the document-helper calculateNow test and the
AFSimple_Calculate doc comment, and adds native and JavaScript multiple-selection cases.

* Patch the callback field snapshot in place instead of rebuilding it

Each field callback rebuilt all field states (3,129 on the benchmark form), and the
retained realm held the previous snapshot, so stamping instance tokens copied it again.
The runner now keeps its last snapshot and patches only the values and flags that
changed; ScriptSession::stamp_fields stamps it before dispatch, the worker copies only
when a token changes, and the realm drops the job's snapshot when the job ends (field
identity is checked against the cached keys instead).

* An oversized job script is that script's error, not a refused edit

Realm::run refused a script too long or too deep to run as an execution refusal, which
made the engine reject the whole edit (setting a 300 KiB calculation script failed). As on
main it is now a plain script error that keeps the value; the realm is not touched.

* Read a leading #! line as a comment in the chain scan; follow main's refusal and conditional limits in tests

The nesting guard from #5079 now checks brackets, prefixes and conditionals; the document
worker's preflight still bounds arrow-function and right-associative chains and skips a
leading #! line as the guard does. A refused script is an error, not a refused edit, so
the preflight test now checks the edit goes through with the error reported.

---------

Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-11 08:42:04 +01:00
Harrison BoothandFredApps d0b17ef95f Add JavaScript push-button caption methods (#5505)
* Add push-button caption script methods

* Apply scripted caption with other field changes

* Complete caption field property initializers

* Apply scripted captions to every button widget

* Format caption regression test

* Cover caption getter errors and redo state

* Assert button caption undo state

* Reject button caption writes during format events

* Test empty push-button captions

* Validate push-button caption updates

* Keep no-widget caption test data alive

* Check caption clipping marker

---------

Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-10 23:21:48 +01:00
Perchenko Anton d47adeff89 M4: bind property drafts with edit-session and replay UI scenarios (#4594)
Binds Properties dialog drafts to the vendored edit-session crate (byte-identical to PerchAnton/edit-session@033f7c3a, ledger in vendor/README) and adds replayable UI scenarios. Includes a merge of main and a test covering the clean Properties inspection-tab live refresh.
2026-11-10 20:22:58 +01:00
Kyle KassenandFredApps 92b965dba3 M10: preserve annotation layers in vector print output (#5019)
* M10: preserve annotation layers in vector printing (#5005)

* #5019 test: a Popup is the annotation that never prints; a Link prints since #5028

---------

Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-10 18:26:50 +01:00
Kyle KassenandFredApps 919db9bd51 M10: preserve NoRotate appearance geometry in vector printing (#5036)
* M10: preserve annotation placement precision (#4995)

* M10: preserve NoRotate and implicit Text print orientation (#5029)

Keep existing printable appearances upright on rotated source pages, including Text annotations whose NoRotate flag is clear.
Preserve original flags and appearance streams, print eligibility and outer page transforms.

* M10: clarify NoRotate verification docs

---------

Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-10 17:04:04 +01:00
FredAppsandKyle Kassen afca38ad71 M10: retain printed artwork with indirect annotation metadata (lands #4668) (#6855)
* M10: retain printed artwork with indirect annotation rectangles

* M10: resolve indirect annotation appearance states when printing

* M10: follow bounded annotation reference chains when printing

---------

Co-authored-by: Kyle Kassen <85040622+KyleKassen@users.noreply.github.com>
2026-11-10 16:05:43 +01:00
905e9abf6f fix(forms): ignore print requests from automatic field scripts (#4166)
* fix(forms): ignore print requests from automatic field scripts

* docs(contributors): opt in to GitHub profile name sync

---------

Co-authored-by: enriquemelzer-bit <319226743+enriquemelzer-bit@users.noreply.github.com>
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-10 15:50:16 +01:00
Kyle KassenandFredApps debb826f29 M10: preserve annotation placement precision (#4995) (#5002)
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-10 15:17:15 +01:00
BFlat 1a159c57fc Merge pull request #6820 from storytold/merge/print-snapshot-area-2491
Print a selected area from Take a Snapshot (lands #2491)
2026-11-10 19:58:04 +07:00
huppifluppandFredApps 8864903795 M10: Recognize text no longer clips the first and last letters of a line (#5058)
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-10 19:23:21 +07:00
FredApps 956935bf0b Merge main into #6820: the area's sheet uses the chosen paper's size, custom papers included (#6830) 2026-11-10 12:36:45 +01:00
regendorf-ux b7cfbd3980 Find and replace text in Edit text mode: a Replace row in the Find box, Replace all as one undo step (#2467) 2026-11-10 15:19:55 +07:00
bflatastic 1726d9aca3 Merge remote-tracking branch 'origin/main' into merge/print-snapshot-area-2491 2026-11-10 14:27:02 +07:00
Hazel Granados 45d51d8c46 M3: a file named with open parameters opens at their destination (#3425) (#5049) 2026-11-10 14:23:54 +07:00
bflatastic 10755a9da9 Merge remote-tracking branch 'origin/main' into merge/mixed-script-2778
# Conflicts:
#	parity/acrobat-features.toml
2026-11-10 10:45:45 +07:00
a71b5124bc M10 #5130: resolve Windows printer-default duplex before spooling (#5180)
* M10 #5130: resolve Windows printer-default duplex before spooling

* M10 #5130: document printer duplex resolution

* M10 #5130: adopt DocumentDuplex driver fix from craft-print

* M10 #5130: adopt two-sided capability selection fix

* M10 #5130: update documented craft-print revision

* M10 #5130: fall back when Windows duplex defaults cannot be read

* fix(print): satisfy duplex review formatting and refresh shared pin

* Repin craft-print to craft-libs main (#411 and #133 merged); ask only the picked printer's driver for two-sided support

craft-libs b6b8a55b has #411 (DocumentDuplex) and #133 (two_sided(name)). The
Printer default support check now reads that one driver instead of listing
every printer's capabilities at submit time (#2192).

---------

Co-authored-by: robertobulltech <341520377+robertobulltech@users.noreply.github.com>
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-10 02:38:14 +01:00
Joaquin ArellanoandClaude Opus 5.5 6914607f17 fix(print): M10 — Windows ya no cambia las letras de las fuentes TrueType incrustadas (#3132) (#4098)
* fix(print): M10 — Windows ya no cambia las letras de las fuentes TrueType incrustadas (#3132)

Un subconjunto TrueType incrustado numera sus glifos de nuevo (en el
subconjunto de Arial de ReportLab el espacio es el glifo 11; en la Arial
instalada, el 3). Al imprimir en Windows, Windows.Data.Pdf → Direct2D →
XPS conservaba esos números de glifo pero los dibujaba con la fuente
instalada del mismo nombre: «Revisión» salía como «Wj{nxn» y la «z» en
negrita como «Ä», tanto en las colas Brother como en la impresora Adobe PDF.

La copia que va a la cola de Windows renombra ahora cada programa
TrueType/OpenType incrustado como PdfCraftPrint<n>, en su tabla name
y en el PDF (/BaseFont, /FontName; el subconjunto conserva su etiqueta),
para que ninguna fuente instalada responda a ese nombre. Glifos,
codificaciones y /ToUnicode no cambian. CUPS y Guardar como PDF reciben
el PDF tal cual.

Tests: extremo a extremo con impose (la página se renderiza idéntica
antes y después, y el test falla sin el arreglo), fuentes que comparten
programa, Type 0, reescritura por plataforma de la tabla name y programas
dañados sin pánico. Falta comprobarlo en una impresora física con Windows.

Fixes #3132

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(print): M10 — solo se renombran en el PDF las fuentes cuyo programa se reescribe (#3132)

Si PdfCraft no puede leer o reescribir un programa incrustado (no es un
sfnt, está dañado o pasa de 64 MiB), ahora conserva también su /BaseFont
y su /FontName. Un visor que tampoco pueda cargarlo seguirá eligiendo el
sustituto por el nombre original («Arial») en vez de por PdfCraftPrint<n>.
Si no queda ningún programa reescrito, el PDF va a la cola tal cual.

Lo señaló CodeRabbit en el PR #4098. Test nuevo:
a_program_that_cannot_be_rewritten_keeps_its_name_in_the_pdf_too (falla
con el comportamiento anterior).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(print): M10 — el renombrado de fuentes para Windows decodifica contra un presupuesto total (#3132)

Cada programa ya tenía un tope de 64 MiB, pero un PDF con muchos
programas distintos podía sumar mucho trabajo de descompresión al
imprimir. Ahora todo el renombrado comparte un DecodeBudget de 512 MiB,
el mecanismo que main acaba de introducir en print. Agotado el
presupuesto, los programas que faltan conservan su nombre, igual que uno
ilegible.

Test nuevo: programs_past_the_shared_decode_budget_keep_their_names
(falla si se decodifica sin presupuesto).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(print): M10 — también se renombran los CIDFont escritos dentro de su fuente Type 0 (#3132)

Si /DescendantFonts lleva el CIDFont como diccionario en línea (en el
propio Type 0 o en un objeto array aparte), el recorrido no llegaba a
él. Cuando compartía programa con otra fuente, el programa se renombraba,
pero el Type 0, el CIDFont y su descriptor seguían diciendo «Arial», y
Windows podía volver a cruzarlos con la Arial instalada. Ahora el Type 0
se trata en el mismo recorrido, sin el segundo que hacía type0_names: un
CIDFont en línea apunta su programa, y al renombrar se cambian el Type 0,
el CIDFont y su descriptor en línea.

Lo señaló CodeRabbit en el PR #4098. Test nuevo:
a_cidfont_written_inside_its_type0_font_is_renamed_with_it (falla sin el
arreglo).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(print): M10 — renamed_table ya no copia cada cadena de la tabla name (#3132)

renamed_table copiaba el texto de cada registro antes de comprobar el
tamaño del resultado: una tabla name de menos de 1 MB con 65.535
registros apuntando a una misma cadena de 65.535 bytes reservaba unos
4 GiB, y un fallo de reserva cierra el proceso al imprimir en Windows.

Ahora la tabla se lee entera sin copiar ningún texto (cada registro
guarda el offset y la longitud de origen) y después cada cadena distinta
se guarda una sola vez: los registros que compartían cadena la siguen
compartiendo y el almacén nunca pasa de lo que alcanzan los offsets de
16 bits. Una tabla que declara más registros de los que caben antes de
sus cadenas se rechaza de entrada.

Lo encontró RomanLis91 en el PR #4098. Tests nuevos:
records_that_share_one_string_keep_sharing_it (falla con el código
anterior) y a_name_table_claiming_more_records_than_fit_before_its_strings_is_refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 01:33:32 +01:00
Osvaldo Duran MelendezandClaude Sonnet 5.5 b00a4be12a Merge upstream/main into pr/print-area
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-09 18:53:16 -05:00
PerchAnton 8dfa52c9b5 Merge main into PR #2778 preserving feature behavior 2026-11-10 01:16:46 +02:00
abb06c70f8 M10: the Print dialog remembers two-sided, grayscale, collate, sizing, comments & forms and Print as image (#2001, #6392) (#2103)
* M10: the Print dialog remembers two-sided, grayscale, collate, sizing and comments & forms (#2001)

Persist the choices that describe how this computer prints and restore
them on the next launch, under the names doc_print takes; copies, pages,
layout, orientation and the printer still start fresh for each job.
Those names now live in one place, pdfcraft_print::names, used by the
tool and the settings file. Settings are untrusted: an unknown name or a
custom scale outside the dialog's 1..=1000 % keeps the default.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* M10: the Print dialog also remembers a booklet's binding side (#2707)

Acrobat keeps the booklet binding (left or right) between prints;
PdfCraft started at Left every time. It is now kept with the other
remembered print choices, named as doc_print names it, and an unknown
saved value keeps the default.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* M10: Print starts each job's copies, pages, layout and orientation afresh (#2001)

CodeRabbit on #2103: the README promised that copies, pages, layout and orientation
start fresh, but open_print carried them over through `..keep` within a session.
ISO 32000-2 Table 147 initialises these per document when the print dialog opens
(NumCopies "typically 1", PrintPageRange), so each opening now resets them to the
defaults (Selected pages still win when thumbnails are picked); two-sided,
grayscale, collate, sizing, Comments & forms, binding, the paper and the printer
picked last carry over as before. Two-sided names now include "printer" (leave it to
the printer, main's default since #2422), so that choice is remembered too.
main's paper-persistence test expected grayscale not to persist; it is one of the
remembered preferences.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* M10: a new print job also resets its layout's own options and leaves Label (#2001)

CodeRabbit on #2103: resetting the layout to Size kept pages per sheet, order, borders,
booklet subset and the poster options through `..keep`, so choosing Multiple again
brought back, say, a cut-and-stack order; and a job printed on Label went back to Size
without giving back the paper Label replaced. open_print now leaves Label through
set_handling (#3564) and resets the layout's own options with the rest of the job's
choices; the binding and sizing stay remembered. The README now says what resets on
each opening and what carries over.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* M10: the Print dialog also remembers Print as image and its resolution (#6392)

A printer that needs pictures keeps getting them after a restart: as_image and
dpi are saved with the other print preferences and restored, a resolution the
dialog doesn't offer keeping the default 300 dpi. The bad-settings checks move
to their own test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyDBXygTf7jcqdsjcfn

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: mtlcl410 <chuanlin@niar.org.tw>
2026-11-09 23:09:03 +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
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
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
bflatastic dd72e2e672 Merge #2345: M6: custom stamps can carry a line filled in when they are placed (#1741)
# Conflicts:
#	ROADMAP.md
#	crates/annot/src/lib.rs
2026-11-09 18:23:14 +07:00
bflatastic c638edf9c7 Merge #2137: M5: comment pop-up windows on the page, with connector lines (comment.popups, comment.connector-lines)
# Conflicts:
#	ROADMAP.md
#	crates/annot/src/info.rs
#	crates/annot/src/lib.rs
#	crates/annot/src/modify.rs
#	crates/annot/src/tests.rs
#	crates/automation/src/comments.rs
#	crates/automation/tests/it/automation.rs
#	crates/engine/src/comments.rs
#	crates/render/src/inspect.rs
#	crates/render/src/inspect/annotations.rs
#	crates/render/src/inspect/model.rs
#	crates/render/src/inspect/tests.rs
#	crates/render/src/lib.rs
#	crates/ui-egui/src/tools/comments/input.rs
#	crates/ui-egui/src/tools/comments/paint.rs
#	crates/ui-egui/src/tools/comments/tests.rs
#	crates/ui-egui/tests/it/comments.rs
2026-11-09 18:22:50 +07:00
bflatastic ca9df2b5fe Merge #4139: Search: keep the match in the middle while a zoom is still on (#3530, builds on #3547)
# Conflicts:
#	crates/ui-egui/src/canvas/find.rs
#	crates/ui-egui/src/canvas/tests.rs
2026-11-09 18:22:37 +07:00
Osvaldo Duran MelendezandClaude Sonnet 5.5 bde2a32875 Merge upstream/main into pr/print-area
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-09 06:17:04 -05:00
mtlcl410 ed6c8afdef Merge remote-tracking branch 'upstream/main' into lane3-2539b 2026-11-09 18:49:37 +08:00
Livio Oswald ba2846cba8 M4: a recovered document's first Save asks where instead of writing the sidecar's path (#3923) (#4327) 2026-11-09 18:33:33 +08:00
mtlcl410 bd74ecab92 Merge remote-tracking branch 'upstream/main' into lane3-2539b
# Conflicts:
#	crates/redact/src/tests.rs
2026-11-09 18:20:12 +08:00
regendorf-ux 08c3d3a5ab feat(ui): split view: two panes, one document or two (#2518) 2026-11-09 18:11:13 +08:00
mtlcl410 c028b51b3d M14: "Combine files in PdfCraft" on File Explorer's PDF menu (#585) (#2503) 2026-11-09 18:10:56 +08:00
mtlcl410 bd5db5dc35 M2: a page whose content was cut at the renderer's limits says so (#623) (#2113) 2026-11-09 18:09:37 +08:00
mtlcl410 2b9829d6f8 Merge upstream/main into fix/redact-metadata-2448 2026-11-09 12:08:16 +08:00
Osvaldo Duran MelendezandClaude Sonnet 5.5 1c82944e0c Merge upstream/main into pr/print-area
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-08 22:04:15 -05:00
bflatastic 08c0a59212 Merge main into merge/redact-forms-misc
# Conflicts:
#	ROADMAP.md
#	crates/render/src/text/tests.rs
2026-11-09 09:56:59 +07:00
BFlat cde331fb7e Merge pull request #6663 from storytold/merge/render-interpret-patches
Land render and font patches (#6292, #6287, #6314, #6353, #6359, #6368, #6409, #6491, #6545, #6516, #6521, #6528, #6533, #6529, #6542, #6543, #6569, #6572)
2026-11-09 10:54:50 +08:00
mtlcl410 b8c8616d05 M14: the Windows installer lets the user choose the install folder (#1139) (#2480) 2026-11-09 10:13:38 +08:00
mtlcl410andClaude Opus 5.5 8c142bef2e Merge upstream/main into fix/redact-metadata-2448
Keeps main's recovery renewal after applying redactions alongside the
combined notification, and reads XMP and rich-text streams with their
/DecodeParms given by reference made direct, as main's stream readers do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
2026-11-09 10:12:29 +08:00
bflatastic a7bc9c5301 Merge #6620: M5: comments keep their formatting and appearance through XFDF and FDF (comment.import-fdf-xfdf, comment.export-fdf-xfdf)
# Conflicts:
#	crates/xfdf/src/xfdf.rs
2026-11-09 08:21:11 +07:00
bflatastic 4c219bb055 Merge #6491: fix(render): a non-embedded Times New Roman draws the glyphs its codes name (hayro-interpret patch 88)
# Conflicts:
#	crates/render/src/raster/tests.rs
#	vendor/README.md
2026-11-09 08:07:55 +07:00
bflatastic a65141ab5f Merge #5761: M3: a snapshot keeps its resolution when zoomed out (#5716)
# Conflicts:
#	ROADMAP.md
#	docs/roadmap.md
2026-11-09 08:07:19 +07:00
Hasan N. ccbfa6d24a M14: localization parity counts every catalog with the i18n report (#5805) (#5894) 2026-11-09 08:40:07 +08:00
Hasan N. bf409db55c M3: pages shorter than the window sit in its middle (#5708) (#5759) 2026-11-09 08:38:40 +08:00
Osvaldo Duran Melendez 9822ec0500 Merge remote-tracking branch 'upstream/main' into pr-fix/print-area 2026-11-08 14:28:16 -05:00
BFlat c07e092ff5 Merge pull request #6637 from storytold/merge/3492-thai-line-breaks
M7: break Thai rows between dictionary words (#3492, merged with main)
2026-11-09 02:25:04 +08:00
mtlcl410andClaude Opus 5.5 b4efe3f78c Merge upstream/main into feat/xfdf-comment-formatting-appearance
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
2026-11-09 02:23:40 +08:00
mtlcl410 31c9d91877 Merge remote-tracking branch 'upstream/main' into lane3-6491
# Conflicts:
#	ROADMAP.md
2026-11-09 02:23:29 +08:00
mtlcl410 ae7eba8df4 Merge remote-tracking branch 'upstream/main' into lane1-2539
# Conflicts:
#	crates/engine/src/edit/run.rs
2026-11-09 02:21:08 +08:00