reading_lines grouped the joined operators by the stream their first token
is in and walked each group on its own. A marked-content sequence opened in
one stream (its /ActualText dictionary, or the whole BDC) and closed in the
next lost its replacement text: the export read "Glyphs" where every reader
of the joined streams reads "Replacement text".
The page's operators are now walked once. Each shown text still counts as
the stream its operator starts in, and text from another stream still starts
a new line, as before.
place_tagged wrapped the page's content in q/Q only when no Wrap stream
existed yet. Content appended after an earlier wrapper (by another tool, or
an older OCR layer) that left a cm, a clip or text state set then moved,
hid or distorted every later header, Bates number, watermark, added text,
flattened annotation and redaction cover.
Placing a mark on top now reads the page's actual operators instead of the
/PCMark tags. When the content parses cleanly with balanced q/Q and closed
text objects and paths, the stretch from the first stream that leaves state
set is wrapped, once, at a stream boundary no comment runs into. Content
that is already self-contained gets no new wrapper, so repeated marks don't
pile up.
Content that can't be read that precisely (stray bytes, unbalanced q/Q, an
unfinished text object or path, too large) is wrapped whole as before,
rather than refusing: redaction stamps its covers after removing the text
and can't back out. A q that content leaves open is closed after it, where
closing it changes nothing already drawn.
The wrapper's close now starts with a newline, so a comment at the end of
the content before it can't swallow the Q. Removing marks strips only
wrapper pairs that end the list, keeping one that later content still
relies on, and recognises the older close bytes too.
Pieces::join separated a page's content streams with a newline, which ended
a comment left open at the end of one stream. hayro, MuPDF and Poppler join
them with a space, so the comment runs on into the next stream and hides its
first line. Edit text, object_list, the redaction audit, redaction and the
Office/HTML export therefore saw text and boxes that nothing draws, and
redacting unrelated text on the page made the hidden content visible: the
rewritten stream dropped the comment.
- Pieces::join uses a space, so every reader of the joined streams agrees
with rendering.
- The parser records, per piece, whether a top-level comment runs into it
and out of it (boundaries only, not every comment). A redaction rewrite
of a piece ends an incoming comment before its first operator and leaves
an outgoing one open, so hidden content stays hidden.
- Reading for export parses the streams joined, instead of one by one.
- The redaction tag check compares the joined streams the same way.
- Pieces::piece_of uses a binary search.
RUSTSEC-2026-0370/0371/0372 were published today for zvariant, zbus_names and
zvariant_derive. All three are unmaintained notices rather than vulnerabilities,
and none has a fixed release to move to. They reach the tree as the D-Bus stack
behind accesskit_unix -> atspi (Linux accessibility) and as a dev-dependency of
pdfcraft-platform, so nothing ships in the other targets' binaries.
This is why main went red today; no dependency version changed.
The canvas asked can_paste_image() on every frame, which opens the OS
clipboard and decodes any image on it. With UI tests running in parallel,
many threads opened the Windows clipboard at once and the editing test
binary died with STATUS_HEAP_CORRUPTION.
- Ask whether there's an image to paste when a right-click opens a menu,
not on every frame. Pasting still reads the clipboard at paste time.
- Route every arboard call through os_clipboard::with, which holds a
process-wide lock across open, use and close.
- stale_clipboard_plain_text_does_not_paste_image no longer writes the
real clipboard; it gets its text from the paste event.
- Run CI tests in parallel again (revert --test-threads=1).
craft-libs#169 is merged, so the fork pin is no longer needed. Pinned to
storytold/craft-libs 82a24b006eefa036b43c09a67fb9a3fbd17ffe63 (main after the merge) rather than the older 12281d07,
which predates resolve_absolute and the Windows colon refusal.
Main added the word-count command, signature-appearance labels, page
transitions, hover previews and the space-usage report; Hindi,
Indonesian and Korean translate all 80, with their ATTRIBUTION.toml
hashes recomputed. The Vietnamese field entries the parallel review
restored read 'trường' (the Microsoft glossary term), and both
registration tests agree on it now.
The fix landed as #2698 (9dfc91e0) with its parity evidence, but no
progress-doc record did: add the status line and progress-log entry in
ROADMAP.md, the status line, revision row and M8 milestone note in
docs/roadmap.md, and gap 6's evidence and revision history in
docs/gaps.md — the wrong-result backlog the issue belongs to.
Estimates unchanged.
The tool panel's back arrow (Back to all tools, in the Edit panel among
others) and Organize pages' back arrow set the workspace to All tools
directly. Pressed from the Edit tab, they left Edit text & images on
under All tools, every paragraph still boxed, and a paragraph open in
the editor still open over the page with its edit not applied.
Both arrows now go through enter_mode, as the mode bar and the Read mode
command do (#3014). Organize calls it once the panel's action has been
handed to the view, since the view borrows the app until then.
Test: editing.rs::the_edit_panel_back_arrow_applies_an_open_paragraph_and_puts_edit_text_down
Test: editing.rs::the_organize_back_arrow_applies_an_open_paragraph_and_puts_edit_text_down
A certification signature's /P was read from the current document, so
a later revision could rewrite P 1 to P 3 and have prohibited changes
judged as permitted. Rewriting the existing SigRef/TransformParams was
itself classified as a signature change, allowed at every level.
/P is now taken from the signature in the signed revision (the one
whose ByteRange ends that revision), and a changed Sig, DocTimeStamp,
SigRef or TransformParams that existed when signed is no longer a
signature change.
Test: a P 1 certification relaxed to P 3 in a later revision, plus a
comment, was Valid with the changes permitted; it is now Invalid.
The Layers panel had no automation tool: doc_info listed the layers, but
nothing could show or hide one, so layer visibility could not be checked
headlessly. layer_set does what the panel's eye icon does, naming a layer
by name (every group with that name, as CAD exporters repeat names) or by
its 1-based position in doc_info's list.
page_render built its own RenderConfig with only the password and the
reading colours, so it ignored layer visibility and comments_hide as
well: hiding comments through the tool changed nothing it drew. The
automation renderer now takes the document's own RenderConfig
(Session::render_config), and both tools drop the cached renderer when
they change a setting.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz
The Font size control on the Fill & Sign bar only set the size of text
typed afterwards; text already placed and picked up kept its size, so the
only way to resize it was to type it again. With a placed Fill & Sign text
or date selected, a size typed into the control (or the end of a drag) now
applies to it through Edit::FontSizeAnnotation, one undo step per change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz
Patch 38 now also replaces the /ColorSpace of a shading that is
DeviceGray, DeviceRGB or DeviceCMYK with the default for it, whether the
shading is painted by sh or as a shading pattern. Poppler and MuPDF draw
these in the default too. The shading's cache key includes the default,
as the image's does.
The forms test also covers a form whose /ColorSpace has no default: it
draws in its page's, as in Poppler and MuPDF.
Notes and file attachments are saved with the NoRotate flag (/F bit 5),
but nothing honoured it: on a page with /Rotate the icon was fitted to
/Rect and turned with the page, and sat away from where it was placed.
The vendored renderer now honours NoRotate (hayro-interpret patch 37):
the appearance fitted to /Rect is turned against the page's rotation
about the rectangle's upper-left corner, which stays put (ISO 32000-2
12.5.3). Form fields and links stay in /Rect, where their click targets
come from. A counterrotated appearance, as stamps use, would be turned
twice by viewers that honour the flag.
Annotation::shown_rect gives the box the note is drawn in. The UI uses
it for hit-testing, outlines, moving, the hover pop-up, the Comments
panel flash and the edit composer; a resize maps it back to /Rect.
comment_add anchors an icon's displayed top-left at `at`, and
comment_list, doc_info and comment_edit use the drawn box.
This also covers the sticky-note part of #1869.
write_real printed a whole real below 1e15 as an integer, and a larger one
through Display, which has no decimal point either. So 4e9 or 1e30 was
written as an integer token outside the range ISO 32000-2 Annex C gives
integers (±2^31-1), and read back as Int (or, in readers with 32-bit
integers, overflowed). Whole reals now use the integer form only within
that range; past it they keep a trailing '.' (§7.3.3 allows "4.").
Raised in the review of #2877.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz