Carry selected tool actions through native file preparation, password retries and conversion, and defer startup intake until pending native opens finish.
Await observable completion in native opening, password, recovery and linked-PDF tests while retaining their content, identity, dirty-state, cancellation and destination checks. Verify the expected validation error and preserve the original document after refused consent targets.
M3; refs #1914.
A stamp placed on a page with /Rotate was drawn in user space, so the
label or picture turned with the page. Counterrotate the appearance so
it reads upright as the page is displayed.
Co-authored-by: Brandon Thomas <[email protected]>
Flattening deleted a cloudy comment it could not draw, and a refused text-box restyle or resize left the new properties in the file. Arrow defaults were stored on plain lines. A custom match ending on a separator included the next glyph, and the vertical-text redaction error claimed an overlap it had not checked.
Co-authored-by: Brandon Thomas <[email protected]>
Glyph boxes of tightly spaced lines overlap, so replacement treated the next line as a duplicate and removed it. A second drawing is removed only when it also shares the edited line's baseline.
Follow up #1237 by deriving Bradford scaling ratios from the source and
D65 white points in LMS. Preserve CalRGB and the merged Indexed/Range
handling. Add independent neutral/chromatic, identity, asymmetric Range,
and degenerate-cone render regressions.
Co-authored-by: Codex <[email protected]>
* M8: Retire inherited redaction resources
* Redaction: pin inherited resources only on redacted pages, shared by reference
localize_resources rewrote every page in the document on every apply and copied a direct
inherited /Resources dictionary into each one, so a large document grew by N x the dict.
Now only redacted pages that inherit resources are pinned; a direct inherited dictionary is
made one indirect object and shared by reference. The parent's /Resources is retired when no
other page still inherits it (the leak fix), and kept (through the shared reference) when an
unredacted page still draws with it. A /Parent chain that can't be followed or disagrees with
the page tree retires nothing. Tests: an unredacted page is left untouched and the rewrite is
bounded; redacting every inheriting page retires the parent's resources. ROADMAP entry moved
into the revision-history table.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
An unchanged classic-table file used to append xref immediately followed by trailer, which qpdf treats as a damaged file. A zero-length subsection keeps trailer-only updates without rewriting any object entry.
Co-authored-by: Brandon Thomas <[email protected]>
* M14: add Lithuanian interface localization
Register Lithuanian UI and date languages with three integer plural forms
and a 2,572-entry contributor-original catalog. Cover dynamic dialog labels,
contextual calendar and certificate wording, commands, tools, and every key
in the other bundled catalogs. Add real-shell calendar, inspector and
password-dialog regressions; preserve PDF values and document state.
Update localization documentation and asset attribution. Native-speaker/VLKK
terminology review remains outstanding.
Validation: cargo xtask ci passed; cargo-deny was skipped because it is not
installed. Five rendered dialogs and contributor manual testing checked UI.
Co-Authored-By: OpenAI gpt-6.1-sol <[email protected]>
* M14: preserve multilingual localization documentation
Restore the existing language descriptions instead of replacing general
localization guidance with Lithuanian-specific coverage. List every
registered language and control-channel code; keep Lithuanian details
alongside the existing catalog descriptions.
Include the previously omitted Kazakh, Polish, Slovenian, Greek and Turkish
catalogs in the shipped-language table without changing the historical
coverage snapshot or existing assessments. Keep Lithuanian roadmap notes
concise and additive.
Validation: all 22 registered languages appear in documentation; every
existing descriptive paragraph is retained. cargo xtask ci passed, with
cargo-deny skipped because it is not installed.
Co-Authored-By: OpenAI gpt-6.1-sol <[email protected]>
* M14: record completed Lithuanian native-speaker review
The contributor confirms they are a native Lithuanian speaker and have
reviewed the translation. Remove obsolete pending-review labels from the
asset manifest and documentation; regenerate ATTRIBUTION.md. Remove the
redundant generated-message disclaimer from the Lithuanian description,
keeping the existing general localization documentation unchanged.
Validation: cargo xtask ci passed; cargo-deny was skipped because it is
not installed. Catalog content and its SHA-256 are unchanged.
Co-Authored-By: OpenAI gpt-6.1-sol <[email protected]>
* Lithuanian: cover main's Copy Image labels, list lt last, check its glyphs
Adds the six Copy Image rows from #1363, moves lt to the end of LANGUAGES
and DATE_LANGUAGES (after tr), adds lt.tsv to the primary-font coverage
test, writes the JavaScript preferences path with '>' as the other
catalogs do (Inter has no ▸), and refreshes counts and hashes.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: OpenAI gpt-6.1-sol <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
* M12: preview text structure proposals for auto-tagging
* Auto-tag preview: no unregistered command, allowed on copy-restricted files like a11y.check
The preview is read-only with no UI command yet, like render_preview, so it no
longer names the Planned a11y.autotag catalog id (tool_table_is_well_formed).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* M12: preview text structure proposals for auto-tagging
* Keep read-only auto-tag preview separate from unavailable command
---------
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
* M7: preserve Arabic text order when copying and editing
Record per-line ActualText for shaped added text and preserve its logical order in Edit text. Cover mixed scripts, marks, copy/search, retyping and save/reopen; retain the drawing golden.
Assisted-by: Codex
* Edit text: keep only right-to-left ActualText out of line joining and bidi recovery
Word and Chrome wrap Latin ligatures in /ActualText spans mid-word; splitting
lines at every span broke such words into pieces in Edit Text. Only spans
whose ActualText has strong right-to-left characters keep their own line and
typing order now. Regression: a Latin fi ligature span stays on its line.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
* M3: use the macOS Finder label in the tab-menu regression
The UI already uses Reveal in Finder on macOS, but the regression test
queried Reveal in File Explorer on every platform. Select the platform's
label while preserving the disabled-action and inactive-tab assertions.
Co-Authored-By: Codex <[email protected]>
* M3: match Greek final sigma in case-insensitive search
Fold capital, normal and final sigma to the same character so Greek words
match in either case. Cover exact search, whole words, glyph ranges and
bounded matches without changing the existing Turkish-I behavior.
Record the search fix and the macOS test portability follow-up in the
roadmap. Workspace tests, all-target Clippy, formatting, wasm, layering
and a synthetic CLI before/after comparison pass on macOS.
Co-Authored-By: Codex <[email protected]>
---------
Co-authored-by: nevicia2010-hub <[email protected]>
Co-authored-by: Codex <[email protected]>
* M14: tune Windows low-DPI mono hinting
* Theme: ignore the raster-sharpness probe test
`windows_hinting_improves_low_dpi_mono_raster_without_changing_layout_or_coverage`
asserts exact egui rasterisation deltas that move with egui upgrades; it is now
`#[ignore]` (run with --ignored when retuning). The tweak and its policy test
stay.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
* M3: follow Windows' Animation effects setting; Smooth scrolling preference
With Settings > Accessibility > Visual effects > Animation effects turned
off, the wheel still eased: egui spreads a coarse wheel step over about a
quarter of a second, for scrolling and for Ctrl-wheel zooming, and has no
switch for it.
- crates/ui-egui/src/motion.rs reads each frame's wheel input the way egui
does, minus the easing, and hands it to the scroll areas and the views
(zoom_delta). A test sums what egui eases and compares it with what is
read at once, and fails if egui stops easing.
- With the system asking for no animations, egui's own animations take no
time and the progress card's bar steps without its sweep.
- The desktop app asks WinRT's UISettings.AnimationsEnabled at launch and
every two seconds of use, so a change applies without a restart.
- Preferences has Smooth scrolling: Use system setting (default), On, Off.
On or Off decides the wheel's scrolling and zooming, and scrolling to a
place, whatever the system says. Saved, settable as smooth_scrolling on
the control channel, translated in all 20 catalogs.
How far a notch scrolls or zooms is unchanged. macOS, Linux and the
browser aren't asked for their setting yet; Off works everywhere.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Credit Jeremy Yao by name in About (contributors/people.toml)
My own entry: real name and display name "Jeremy Yao".
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* M3: rename Smooth scrolling to Animation effects; it decides every animation
The preference also governs Ctrl-wheel zooming, so "Smooth scrolling"
described only part of it. As "Animation effects" (Use system setting, On,
Off) it now decides every animation in the window, the way the Windows
setting of the same name does:
- the wheel's scrolling and zooming, and scrolling to a place (as before);
- egui's own animations, the progress card's sweep, and the chrome's hover
and press washes (new on main, with durations of their own), which used
to follow the system alone or not at all.
Saved and set on the control channel as animation_effects (system, on,
off); the unreleased smooth_scrolling name is gone. The three labels are
retranslated in all 20 catalogs.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Tests: the app's two real-GPU tests take turns (FreeBSD SIGSEGV)
FreeBSD CI died with SIGSEGV in the pdfcraft binary's tests on this branch
(d4b928f1). The log shows a_gpu_error_while_a_window_is_set_up... (started
first, still running) and pipeline_creation_error... (started shortly
before) both in flight when the process died: two test threads inside the
graphics libraries at once. Nothing else still running was native code.
Both now take one lock for the whole test, as the UI tests already do for
the same reason (crates/ui-egui/tests/view.rs). Each takes about two
seconds with a device, which is why they can overlap.
The FreeBSD job has been failing at the same step with the same exit code
on main (84a75eae, 4a1e205f, 3d2bdfe7: every completed run since #1042
added the second real-GPU test) and on unrelated PRs. Their logs weren't
available to confirm it is the same crash.
Not reproduced locally (no FreeBSD machine here); the next FreeBSD run is
the check.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
* M7: open local GoToR PDF links natively
* GoToR links: read only regular .pdf files under a size cap; add missing translations
A GoToR link in an untrusted PDF could name /dev/zero (unbounded read), a FIFO
(UI thread hangs) or a directory. Both the UI path and the `link_open` tool now
go through `pdfcraft_engine::read_remote_document`, which requires a `.pdf`
extension and a regular file (metadata checked before opening) of at most
1 GiB, and stops reading if the file grows past the cap. Regression tests cover
directories, a /dev/zero symlink and a FIFO (unix) in the engine, the tool and
the UI.
Adds the four link notifications to all 20 catalogs and "The existing action
will be preserved." to el, es, pl, te and zh-hant.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
* Gates: fix two clippy failures on main
- ocr_ui: "Also recognize pages that already have text" used egui's own
checkbox, which clippy.toml disallows (#1184 landed beside #1173);
use widgets::checkbox like every other box.
- camera_edges: Rust 1.97's manual_range_contains; the rewrite keeps the
old answer for a NaN angle (false) with an is_finite check.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_019ojKsSCHWk2AuyDTFMHCd7
* M10: print from the web build through the browser's print dialog (gap 4)
The web build had no printer: spool::submit refuses on wasm, so Print
could only download the print-ready PDF. Now its Print dialog offers
"Browser's print dialog" (the default there), which reaches every
printer the operating system knows.
- web_print: PdfCraft draws the print-ready PDF's sheets itself
(engine Exporter), one sheet a frame since wasm has no threads:
300 dpi up to 100 sheets, 200 up to 300, 150 up to 1,000, at most
64 MP a sheet and 1 GiB of PNGs a job. The PNGs become blob URLs
and print from a hidden srcdoc iframe, one sheet per page, margin 0.
- Chromium prints every page at the default @page size, so a sheet of
the paper's size turned sideways is rotated 90 degrees CCW onto it
(as drivers do); other sizes get named @page rules.
- Copies, two-sided and colour are greyed out (the browser's dialog
sets them). If print() is refused (e.g. a sandboxed frame), the
print-ready PDF downloads instead, with the reason.
- pdfcraft-print stays free of web APIs; six new strings in all 20
catalogs (ATTRIBUTION hashes refreshed); docs and parity updated,
gap 4 closed.
Verified in headless Chromium against a trunk build: three sheets at
300 dpi, the landscape sheet turned, no blank trailing page, and the
download fallback. Firefox and Safari not yet tried.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_019ojKsSCHWk2AuyDTFMHCd7
---------
Co-authored-by: Claude <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
* M0: keep the camera edge test NaN-safe under clippy's manual_range_contains
Clippy 1.97 flags `d < 0.35 || d > PI - 0.35` in the camera edge hit test. Its suggested
`!(0.35..=PI - 0.35).contains(&d)` would count a NaN direction as a hit, which the two
comparisons did not, so the NaN check is kept explicitly. Behaviour is unchanged.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011AsuqvnFXhY9ASL1bA2jtm
* M14: edits let go of the previous working file before writing the next (gap 13)
Every edit writes a new working file: the original plus one appended revision. The previous
one stayed alive in the working bytes, the display bytes and the renderer while the next was
written, so after a few edits a 1 GiB file peaked at three copies.
Each refresh path (full, comments/form, content, undo, redo, after save) now releases them
first: the working and display bytes fall back to the original (already held by the editor)
and the renderer is replaced by an empty one until the refresh rebuilds it. A refresh that
still fails after rollback draws the original instead of nothing. Save still writes from the
editor, never from these.
Measured on a synthetic 1 GiB file (release build, Linux): five edits peak at 2.1 GiB instead
of 3.1 GiB, in 8.5 s instead of 16 s. Saving still peaks at three copies; reading from disk on
demand stays blocked on the renderer (hayro parses one contiguous buffer, gap 2). gaps.md,
the parity notes and the roadmap record both.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011AsuqvnFXhY9ASL1bA2jtm
---------
Co-authored-by: Claude <[email protected]>
* #1092: Add editable Organize page-range selection
Generated with Codex.
* #1092: Leave overlapping main CI cleanup to PR #1167
Generated with Codex.
---------
Co-authored-by: Brandon Thomas <[email protected]>
* M10: keep invoice overlays out of Word body flow (#773)
Export inferred tables without visible borders. Keep text and images
positioned on pages with artwork, rotated or large text, and retain
each source page's size, crop rotation and units.
Cover invoice conversion through the automation tools, and handle
unavailable Windows symlink setup in the confinement test.
Co-authored-by: Codex <[email protected]>
* M10: add @lollinoo's chosen contributor credit (#773)
The contributor requested their public GitHub profile name while preparing the #773 PR.
Co-authored-by: Codex <[email protected]>
* Word export: float a page only when text overlaps an image or watermark
positioned() turned every page with any image, or with text twice the body
size, into absolutely positioned VML text boxes, so a page with a logo or a
big title lost its flowing paragraphs, headings and tables. Now a page floats
only when it has rotated text, or when an image or a watermark-sized text
block actually overlaps other text (bounded pairwise test). Other pages flow
with images inline. Adds a regression test for a page whose image and title
sit clear of the text, and updates the docs and parity notes.
---------
Co-authored-by: Codex <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
* M0: remove upstream trademark artwork from contributor fork
Use the existing document icon and a plain project label. Remove trademark
asset entries and regenerate attribution as required for modified forks.
Co-authored-by: OpenAI Codex <[email protected]>
* M7: group compatible PDF words and hide source text during editing
Join compatible words across text objects and subset-font spaces, recognize
component colours, and reuse subset fonts with numeric space positioning.
Render a read-only background with the selected glyphs removed while the
inline editor is open. Keep one frame and source line breaks, and reset
the layout width when switching paragraphs. Expose the same preview through page_render.
Add synthetic extraction, save/reopen, preview and UI regressions. Record
the remaining mixed-style paragraph and installed-font limitations.
Co-authored-by: OpenAI Codex <[email protected]>
* M7: preserve rich PDF regions and preview text edits in place
Group mixed source runs into complete visual regions, retain run styles and source encodings, and use validated embedded source faces in the inline editor. Preserve source baselines and show a single live frame as text grows or shrinks, backed by a read-only draft geometry tool.
Validation: strict workspace Clippy, workspace tests, all 30 WASM crates, asset and parity gates, licensed synthetic edit/save/reopen and desktop checks, and an opt-in four-page private-document regression.
Co-authored-by: OpenAI Codex <[email protected]>
* M7: keep cropped artwork from blocking text editing
Track page/path clipping separately from full image placement, use visible selection bounds, and prioritize text hit testing over overlapping artwork. Preserve fixed clips during image transformations and expose visible bounds through the headless tools.
Validation: strict workspace Clippy, workspace tests, 30 WASM crates, asset/parity gates, synthetic engine/tool/UI and native desktop checks, both private-document UI regressions, and all-page local edit/save/reopen/undo on a four-page cropped-artwork PDF.
Co-authored-by: OpenAI Codex <[email protected]>
* M7: resize cropped images with their clipping paths
Keep the visible frame and image pixels under the same transform. Preserve the
opposite corner and respond to diagonal, horizontal-only and vertical-only
corner drags without jumping from an off-centre grip. Refuse shared clipping
scopes that would move unrelated content.
Add synthetic engine/tool/UI regressions and opt-in private-file coverage
for 80 corner gestures and 10 grow/shrink save/reopen/undo render checks.
Co-authored-by: OpenAI Codex <[email protected]>
* M7: complete source font subsets and preserve clipped editing
Add explicit document fonts, CFF embedding, range formatting and bounded contextual shaping; isolate shared image clips and verify private Chinese edits on all pages.
Co-authored-by: OpenAI Codex <[email protected]>
* Revert "M0: remove upstream trademark artwork from contributor fork"
This reverts commit 3aa539b5b6.
* Test: give the text layer up to 4 s before copying (it flaked on a loaded machine)
---------
Co-authored-by: Kamoliddin Fatkhullaev <[email protected]>
Co-authored-by: OpenAI Codex <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
* Issue #1028: OCR can read pictures on pages that already have text
Recognize Text skipped every page with text, so a picture of text on a
page that also has real text never became searchable. The engine and
the ocr_recognize tool already had skip_text_pages, but the desktop
dialog never offered it, and turning it off read the page's own text
again and added it a second time, so search found every word twice.
- Engine: always collect the page's own glyph boxes; with
skip_text_pages false, a recognised word at least half covered by
them (an earlier OCR layer included) is left out. OcrPage counts
those words as already_on_page. The default still skips pages with
text.
- Dialog: "Also recognize pages that already have text", kept with the
other choices and used by Recognize text in multiple files too.
- Tools: ocr_recognize reports already_on_page; ocr_recognize_files
accepts skip_text_pages.
- The two new labels in the 15 catalogs that translate the OCR dialog.
- Synthetic tests (a picture of a sentence plus real text) for the
engine, the tool and the dialog; the engine test fails with the
filter turned off. Unit tests for the coverage check, including
NaN, infinite, inverted and overlapping boxes.
- parity, docs/roadmap.md M10 row and the ROADMAP.md progress log.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01JqiZ658tGndQaHao5Q6mdm
* Issue #1028: Czech labels for the OCR text-pages option
The Czech catalog was completed (#1066) while #1028 was in review, and
czech_covers_ui_literals requires every tl! literal: the two new
Recognize Text labels were missing, so the test failed after the merge.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01JqiZ658tGndQaHao5Q6mdm
* Contributors: credit rp6186030 as Raj Patel in the About window
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01JqiZ658tGndQaHao5Q6mdm
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: rp6186030 <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
Reuse a replaced named comment's object reference so omitted replies and
review statuses remain attached. Keep popup replacement behavior and let
the final duplicate record control its deferred reply relationship.
Resolve indirect names in existing PDF comments so updates match their
original objects instead of creating duplicate parents.
Cover existing-PDF updates, incremental and full saves, subsequent FDF
exchange, page-scoped names, unnamed additions, duplicate records and
indirect names with surviving reply and review-status references.
Co-authored-by: MMexicann <[email protected]>
Co-authored-by: Codex <[email protected]>
* M7 #594: preserve ordinary paragraph drags (source-only GGEO candidate) [skip ci]
Route body drags through source-preserving MoveObjects, bind gestures to
the document generation, and keep added-content input ownership with
the Edit panel open or closed. Add nine real-shell source regressions.
Source-only transfer to the owner's fork, explicitly authorized before
validation. Independently source-reviewed; formatting, builds, tests,
rendering and all gates remain pending on ggeo-ai02. No upstream PR.
AI-assisted with OpenAI.
* M7 #594: record validated ordinary paragraph drags
Format the source-reviewed candidate and record successful GGEO validation:
focused UI/engine tests, exact-base source loss, native drag/history/save/reopen,
independent Poppler checks, and all eight repository CI gates.
Credit: @FredApps
* M7: use generic validation wording
* Tests: pin the clock where two saves or combines are compared byte for byte
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: FredApps <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
* fix(theme): complete Linux System appearance tracking
Follow up on #881 for #446 with the standard numeric appearance portal setting
and event-driven updates that wake idle windows. Keep manual modes independent,
cache their desktop updates without repainting, and cancel the worker on close.
Retain inherited native window appearance and populate both egui style branches
with the chosen palette. Preserve saved System, the Light default and unknown
source fallback, and avoid desktop session access in headless UI contexts.
Assisted-by: Codex (gpt-6.1-sol)
* Desktop theme: keep the GNOME colour-scheme fallback XFCE needs
The portal tracker read only org.freedesktop.appearance, which XFCE's portal
doesn't answer (it proxies the GSettings schemas). It now also reads and
subscribes to org.gnome.desktop.interface color-scheme and uses it when the
freedesktop setting states no preference, as main's reader did. KDE answers
only the freedesktop one, which wins when it states a preference.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
* M10.5: Restore architectural paper presets and PDF scale controls
Port the missing paper catalog and scale controls from PR #599 onto the merged Windows printing implementation. Keep the spooler and background discovery from #847/#1007. Document the feature-by-feature audit and verification limits.
Assisted-by: OpenAI Codex
* Drop the provenance write-up and the screenshot example (the kittest covers the dialog)
* Refresh catalog hashes
---------
Co-authored-by: Brandon Thomas <[email protected]>
* M4: document the directly accessible page overview
Part of the organize-page-overview change.
Co-authored-by: Codex <[email protected]>
* M4: open Organize in the page grid with selection and per-page actions
Show the overview from the tool catalogue, Home, palette and control channel. Add checkbox selection and local rotate/delete actions; preserve thumbnail aspect ratios.
Co-authored-by: Codex <[email protected]>
* M4: translate page selection and local actions
Co-authored-by: Codex <[email protected]>
* M4: cover overview entry, selection and page actions
Co-authored-by: Codex <[email protected]>
* M4: record the organizer workflow improvement
Co-authored-by: Codex <[email protected]>
* M4: link page overview regression evidence
Co-authored-by: Codex <[email protected]>
---------
Co-authored-by: Codex <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
The parity and roadmap docs were last refreshed before a batch of fixes
merged, so they still described closed issues as open problems.
- #774 (encrypted output rejected by Acrobat, fixed by #836): gap 1
removed from gaps.md; its remaining interop-suite work moved to gap 12.
Gap numbers are kept so existing "gap N" references stay valid.
- #756 (Windows printing, #847): Printers row, Print area and roadmap
rank 1 now name web printing as the remaining gap.
- #740 column select (#765), #759 1:1 touchpad scrolling (#868),
#810 Shift-Cmd-G (#835), #825 (#822).
- #844 multi-object move (#907): marked partial, same page only.
- #799, #800, #807, #809, #811, #815-#819, #821 (incl. the #816 panic):
gap 6 and the area tables list them as fixed.
Scores, readiness percentages and the stage are not re-judged; only the
rank-0 estimate drops by gap 1's 8-15 h (40-70 -> 32-55).
Co-authored-by: Brandon Thomas <[email protected]>
* fix(forms): refresh the editor after accepted Tab edits
* test(forms): keep values through same-field Tab and Save
* docs: record accepted-value Tab and Save behavior
* docs: log verified Tab save regression
---------
Co-authored-by: Brandon Thomas <[email protected]>
* fix(forms): encode appearances with the chosen font
* docs: record form font encoding limits
* docs: log verified form encoding regressions
---------
Co-authored-by: Brandon Thomas <[email protected]>
* M13: report unavailable symbolic-link fixtures in hostile-argument tests
Only include the planted link escape when symlink creation succeeds. On
non-elevated Windows the fixture can fail with OS error 1314; exercising
its nonexistent path otherwise produces false confinement leaks. Keep
all remaining traversal and absolute-path cases and report the skip.
Co-authored-by: Codex (GPT-6) <[email protected]>
* M3: return renderer initialization errors to the OpenGL startup fallback
Guard renderer creation with the existing scoped GPU-error handler and
return CreateRenderer instead of invoking wgpu's default panic handler.
This lets Auto startup reach its existing OpenGL retry before app creation.
Add a real-device invalid/valid pipeline regression and Windows startup
reproduction notes. The host-specific DX12 shader compiler error itself
is not fixed; explicit renderer choices and the non-winit path are unchanged.
Co-authored-by: Codex (GPT-6) <[email protected]>
* Leave the symlink-test fix to #949, which covers the same ground
---------
Co-authored-by: Codex (GPT-6) <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
Add Watermark / Update Watermark can now move the mark from the page
centre by a horizontal and a vertical offset in points (right and up).
- edit: add_watermark refuses a non-finite offset instead of writing it
into the content stream; tests for the placement and the refusal.
- automation: doc_watermark takes offset_x and offset_y (clamped to
+-20,000 points); a test saves, reopens and measures the text moving.
- ui-egui: an "Offset from centre" row with Horizontal and Vertical
fields; the preview follows it for text and for picture watermarks.
- i18n: "Offset from centre" in the catalogs that have a coverage test
(ar, bg, de, fr, hu, it, ja, pt-br, ru, uk, zh-hans); hashes updated in
ATTRIBUTION.toml.
- parity and roadmap: edit.watermark-appearance stays partial (no offset
from the page edge, no print/screen-only variants, no repeat); image
and PDF watermarks no longer listed as missing; progress log line.
Co-authored-by: Brandon Thomas <[email protected]>
* Print: Windows lists its printers and spools jobs (#756)
The Print dialog's printer list comes from Win32_Printer through PowerShell's
CIM (wmic is gone from Windows 11), and jobs are spooled by the embedded
windows_print.ps1: the in-box Windows.Data.Pdf renders each sheet at the
printer's own resolution and System.Drawing.Printing carries copies,
collation, duplex and colour as the job's settings. Both run through
powershell, so the Rust code touches no Win32 API. Fixes#756, with the
printer-not-showing duplicates #160, #244, #293, #465 and #644; CIM approach
from #452. On CI a paused Generic / Text Only test printer catches the job in
its queue; a parser test keeps the script valid PowerShell.
* Print: fix the Windows await helper and render the job on CI (dry run)
Real-machine testing found [System.WindowsRuntimeSystemExtensions]::GetMethods()
failing with 'does not contain a method named GetMethods': GetMethods is an
instance method of [Type], so it is called with '.', the form the canonical
WinRT-await snippets use, not '::'. The first CI run missed it because the
end-to-end test skipped silently when the runner refused the test printer, so
the script had never actually run.
The script now honours PDFCRAFT_PRINT_DRYRUN=1: render every sheet with
Windows.Data.Pdf to PNGs in the temporary folder and print nothing. The test
runs that half unconditionally, so CI exercises the whole WinRT path —
projection, await helpers, render — on any machine, while the paused-printer
half stays best-effort and prints why it skipped. Win32_Printer enumeration
asks only for Name and Default, so a machine with nine printers waits less.
* Tests: the find-options wait in the viewer test is a deadline too
4280f83 converted the frame-count waits in this test to deadlines after the
same 12-of-15 race under a full workspace test run, but left the first wait —
the one for the 'page' matches — on the old 60-frame loop, and it flaked the
same way on PR #847's CI. Same fix: wait up to 20 s for the 15 matches, then
assert.
Progress docs per craftrules standards/progress-docs.md: target-app parity, gaps, roadmap with alpha gate, readiness by audience (full / mainstream / essentials) with Opus 5.5 hours, and feature, format, PDF-spec, hardware, UI and localization parity docs.
Co-Authored-By: Claude Opus 5.5 <[email protected]>