Commit Graph
4066 Commits
Author SHA1 Message Date
FredApps cc986fa289 Merge origin/main into feat/jbig2-run-allowance 2026-11-01 21:06:29 +01:00
07582e9ed4 Make MCP aligns enums compatible with Kimi (#5592)
* M13: make MCP aligns enums Kimi-compatible

Fixes #5588

* Drop the progress-log lines that conflict with main

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

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 15:05:43 -05:00
PiohrunandClaude Opus 5.5 036811368b M2: both ends of a /Decode array have to be numbers to invert an export (#5678)
An end that is missing or isn't a number sorted below any number, so [1],
or [1 7 0 R] with 7 leading nowhere, read as inverted on a JPEG or a stencil
mask, and so did an end too long to hold, which parses as infinite. Such an
array now leaves the default mapping, as it does on the lossless path.


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

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 15:05:26 -05:00
Livio OswaldandClaude eafe9e2c0b M8: typing the last page of a range keeps what is typed (#5574) (#5579)
* M8: typing the last page of a range keeps what is typed (#5574)

The page-range dialogs (Redact pages, Rotate pages, Duplicate field,
Number pages) raised the end to the start on every frame, so the
half-typed "1" of "12" became the start before the "2" arrived.
The end is now ordered only once its field is no longer being typed
into. Number pages no longer lowers the start to a half-typed end, and
its preview cannot underflow while the end is below the start.

* M8: a test types the last page of Rotate Pages' range (#5574)

Rotate Pages' From and to fields are labelled, and a test types "12" after a
first page of 5 (pages 5-12 are turned) and "3" left by clicking OK (page 5
alone), as croquete1 asked on #5579.

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

* M8: page ranges stay typed while the window is in the background, and OK orders them (#5574)

Review follow-up. The end field's typing check used Response::has_focus,
which is false while another window is in front, so switching apps
halfway through "12" still raised the typed "1" to the start. It now
asks egui's memory (widgets::typing_into). OK pressed while the end is
still focused (a screen reader's click) orders the range first in Rotate
pages, Duplicate field and Redact pages, and Number pages builds its edit
from the ordered end, so a reversed range never reaches the edit.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-11-01 15:05:01 -05:00
Livio OswaldandClaude Opus 5.5 901050a31f M14: the comments panel lays out only the cards in view (#5488) (#5583)
* M14: the comments panel lays out only the cards in view (#5488)

With more than 100 comments, a card or page header out of view that
was measured at the current width only takes up its height instead of
being laid out every frame. The selected card is always drawn, so it
still scrolls itself into view. Shorter lists are laid out whole and
keep every card in the accessibility tree.

The 500-comment panel in tests/perf.rs drops from about 23 ms to 5 ms
per frame locally, well inside the 40 ms budget it overran on CI.

* M14: the comments panel measures a card again when it changes (#5488)

A card's kept height is now per document and per what the card shows (its
thread's text, author, date, status, colour and lock, and whether it is the
selected card), so another document at the same width, an edit, an undo or a
redo never lays the cards below it out at a stale height (CodeRabbit on #5583).

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

* M14: a comment card with an editor open is never skipped (#5488)

A card with an inline editor open on it or on one of its replies is laid out
wherever it is, and its kept height is apart from the one without the editor,
so the cards below make room for the editor (CodeRabbit on #5583).

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-11-01 15:04:57 -05:00
Livio OswaldandClaude Opus 5.5 2242eb322f M10: Create ▸ Blank page uses the system region's paper (#5644) (#5651)
* M10: Create ▸ Blank page uses the system region's paper (#5644)

A new blank document was always US Letter. It now takes the paper of the
system region: Windows' own Region paper size (iPaperSize) first, then the
system locale on macOS or LC_ALL/LC_PAPER/LANG, A4 everywhere outside CLDR's
US-Letter regions, and Letter when the region can't be told (web).
The region parsing is shared with the Units preference.

* M10: the first locale variable set decides the paper; extensions are not regions (#5644)

LC_ALL, LC_PAPER and LANG are read in POSIX order and the first one set
decides, so LC_ALL=C no longer falls through to LANG's region; and a locale
tag's region is read from its base tag only, so en-US-u-nu-latn is US, not
NU (CodeRabbit on #5651).

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

* M10: the blank page test covers A4 as well as Letter (#5644)

The app keeps the paper Create ▸ Blank page makes (blank_paper, the system
region's at start), so the test makes a blank page on A4 and on Letter
whatever the host's region (CodeRabbit on #5651).

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-11-01 15:04:52 -05:00
Livio Oswald a74e3d4715 M3: the wheel scrolls right after Alt+Tab back, before the mouse moves (#1518) (#5608)
After switching back to the window, the windowing layer sends no
pointer move until the mouse moves, so egui knew no pointer and the
wheel scrolled nothing. When a frame turns the wheel with no known
pointer and no move of its own, the raw-input hook now asks the system
where the pointer is (drag_pointer::in_window, already used for file
drags) and puts that move first.
2026-11-01 15:04:47 -05:00
Guillem Hermida 778aa58522 tests(engine): the XFA opening scale test times its small and large forms in the same rounds (#5586)
The test timed the 100-field form three times, then the 800-field form
three times, and compared the best of each. A busy spell on a shared
runner that fell on the second half slowed only the large form, and the
ratio went past 16x (16.6x on a gate run) though it is about 7x.

Each of five rounds now opens the small form and then the large one, and
the best round's ratio is checked against the same 16x, after one
untimed opening of each. With the values filled one by one again (the
quadratic code before #4638) it still fails, at about 48x.
2026-11-01 15:04:42 -05:00
NetterSilverandClaude Haiku 5.5 2289b5755d Ignore a negative trailer /Size in incremental saves (#5566)
Found while testing crates/cos/src/writer.rs:248

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-11-01 15:04:36 -05:00
NetterSilverandClaude Haiku 5.5 fdaa502f27 Reject signed and empty arcs in try_oid (#5581)
Found while testing crates/sign/src/der.rs:467-472 (try_oid)

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-11-01 15:04:32 -05:00
FredApps 2cd50b8d39 Merge pull request #5491 from Piohrun/fix/jbig2-retained-bitmaps
fix(render): a JBIG2 page's segments are bounded in what they hold and refer to (hayro-jbig2 patches 5 to 9, hayro-syntax 29)
2026-11-01 21:04:29 +01:00
Grzegorz MartensandClaude Opus 5.5 b57ddb0a22 Merge upstream/main
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
2026-11-01 20:10:05 +01:00
aiongg 41652972ac Merge pull request #5539 from Piohrun/fix/indexed-lookup-by-reference
M2: a reference in a colour space or array isn't lost: Indexed tables, Pattern spaces, /Decode, /W and functions
2026-11-01 13:59:05 -05:00
Brandon ThomasandClaude Opus 5.5 7d78f3e144 Release 0.17.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
v0.17.0
2026-11-01 13:58:27 -05:00
VoiceLessQ 424ca0e972 M14: Preferences sets how many recent files to keep (#5572) (#5675)
The list was fixed at 12. Preferences ▸ Documents and view now takes a
number from 0 to 50, with 12 as the default. At 0 Home has no Recent
section and File ▸ Open Recent is disabled.

The list is cut when Preferences closes, so the number can pass through
0 on its way to another. Until then Home and saved settings already
leave out what is past it. A settings file can't ask for more than 50.

The control channel and launch options take it as recent-files. The two
new strings go in every catalog as English copies.
2026-11-01 13:52:47 -05:00
aiongg 4238670dd5 Merge remote-tracking branch 'o/main' into fix-5539
# Conflicts:
#	crates/create/src/tests.rs
2026-11-01 18:48:28 +00:00
aiongg 6818995a3c Merge pull request #5673 from Piohrun/fix/jbig2-region-location
fix(render): JBIG2 arithmetic near the end of an i32 doesn't panic (hayro-jbig2 patch 12)
2026-11-01 13:45:39 -05:00
FredApps 67e86f2b27 Merge pull request #5620 from Piohrun/fix/mask-resample-allocation
fix(create,optimize): a mask of other proportions doesn't take the process down
2026-11-01 19:44:58 +01:00
FredApps b3023b4b28 Merge pull request #5624 from Piohrun/feat/xfa-rotate
M12: an XFA draw placed by position turns about its anchor
2026-11-01 19:43:57 +01:00
FredApps 61140ed807 Merge pull request #2155 from Combiler01/main
feat: Acrobat UI parity for image editing, text formatting, and UI stabilization and Bug Fixes
2026-11-01 18:50:01 +01:00
Grzegorz MartensandClaude Opus 5.5 10107d943a M2: JBIG2 arithmetic near the end of an i32 doesn't overflow
A region's location, a refinement's offset, a symbol's corner, a Huffman
range line and a decoded integer of 2^31 could each overflow: a panic
wherever overflow is checked. The last four wrap, as a release build did.
Bitmap::combine saturates, which comes to the same: a side is at most
65,535, so a location that overflows is past the end of any page. What is
drawn doesn't change. Patch (12), after the numbers #5491 and #5569 take.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
2026-11-01 18:32:33 +01:00
Dylan M. Taylor 7ca642980a docs: sync Craft App Suite list with ArtCraft Launcher 2026-11-01 12:29:59 -05:00
FredAppsandCodex GPT-6.1 a9de3db628 docs: record image editing review fixes and movement semantics
Validated with 3231 passing scoped tests (10 skipped), clippy, wasm checks, repository gates, and 42 CLI smoke steps including saved-document verification.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
2026-11-01 17:59:35 +01:00
FredAppsandCodex GPT-6.1 6816d14e02 Fix context image placement and canvas selection ownership
Convert context-paste user coordinates into AddImage display coordinates and
identify the inserted image through its new owning stream and XObject. Keep
legacy added-image metadata aligned with the active image controller, route
Delete to the visible selection, and clear hidden image selections when leaving
the controller while preserving text selections and drafts.

Separate selection-dependent Copy from whole-page Snapshot and document Export
permissions. Add synthetic UI regressions covering transformed page placement,
identity collisions, shared image references, saved deletion results, tool
transitions, and permission controls.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
2026-11-01 17:54:15 +01:00
FredAppsandCodex GPT-6.1 75e012de9a fix(edit): compose inside-scope group translations in order
Fold a leading transform inside the image scope as cm followed by the local transform; an enclosing transform uses the opposite multiplication order. This preserves the complete requested image and crop displacement under an outer scale. The exact crop-arrange-group-move fixture previously moved only five points for a ten-point request; saved geometry and rasters now match an independent direct Transform control across both axes and signed offsets. Full scoped Linux native, wasm and repository gates pass.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
2026-11-01 17:41:13 +01:00
FredAppsandCodex GPT-6.1 e677c009b3 fix(edit): restore inherited text state when arranging Forms
Track the text-state operators with saved drawing state, restoring inherited spacing, scaling, leading, rendering mode, rise and known font before relocated Form artwork. Emit restoration inside BT/ET, and leave a font selected by a replayed ExtGState authoritative over an older direct Tf. The exact inherited 12 Tc fixture failed its saved-PDF raster comparison before this fix; zero-spacing and destination-state controls now preserve rendering. Scoped Linux native, wasm, clippy and formatting checks pass.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
2026-11-01 17:41:13 +01:00
FredAppsandCodex GPT-6.1 8669aa48aa fix(edit): preserve graphics state chronology and mask identity
Replay repeated ExtGState names in last-application order. Compare each complete soft-mask value and its establishment matrix instead of only its group reference, and retain cached shared definitions across saved states. Saved-PDF raster regressions cover Alpha versus Luminosity over the same group, repeated aliases at different matrices, and ordinary sequence/single-mask controls. Definition checks also cover backdrop and transfer parameters. Actual baseline and reverted-comparator tests fail; scoped Linux native, wasm, clippy and formatting checks pass.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
2026-11-01 17:41:12 +01:00
FredAppsandCodex GPT-6.1 fdb6a6f33e fix(ui): rotate cropped image previews around the committed pivot
Project the visible user-space bounds centre for the drag preview, matching the RotateBy engine operation. The full image centre differs for cropped artwork and caused the preview to jump on release.

The regression compares actual painted preview corners with saved/reopened image corners and verifies a requested 90-degree turn on cropped and uncropped controls, including page rotation. Linux scoped clippy, 106 tests, wasm, formatting, layering and assets pass.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
2026-11-01 17:34:13 +01:00
FredAppsandCodex GPT-6.1 c0a5a5cbf8 fix(ui): resize image frames relative to the captured press
Invert the actual affine basis instead of projecting onto assumed orthogonal axes. Capture the displayed crop frame for handles and apply its relative transform to the full artwork, preserving author clips on rotated pages. Exact out-and-back gestures preserve bytes and undo state, including off-centre presses.

Synthetic headless regressions verify sheared and rotated images, crop-frame anchors, press-offset independence and saved/reopened placement. Degenerate and nonfinite bases are refused; the inverse guard has a negative-control test.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
2026-11-01 17:34:13 +01:00
FredAppsandCodex GPT-6.1 393bd30701 fix(ui): leave source text untouched when script conversion is a no-op
Only request a script conversion from the panel; the caller decides whether conversion changed the text. Do not create a paragraph rewrite merely because the button was clicked. A hidden QQQ fixture checks both script buttons preserve document bytes, undo history and saved rendering, while supported conversions remain covered. Actual reverted-fix raster failure and scoped Linux native, wasm, clippy and repository checks passed.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
2026-11-01 17:19:21 +01:00
Grzegorz MartensandClaude Opus 5.5 89fed9a9e6 M2: the chain tests want std, like the module's other thread tests
They use std::thread and std::sync::mpsc, so they take the same gate, and
so does the helper only they use. The crate's test build doesn't compile
without std on main either, for reasons of its own; these add nothing to
that.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
2026-11-01 17:17:59 +01:00
FredAppsandCodex GPT-6.1 2ab9c6992c docs(edit): record latest PR 2155 review fixes
Record delivered clipboard events, the mixed-size display correction, and explicit mixed-script normalization with Undo. Combined scoped Linux validation passed: 2785 tests, clippy, doctest checks, wasm, formatting, layers, assets, parity, and a 26-step CLI smoke test.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
2026-11-01 16:38:24 +01:00
FredAppsandCodex GPT-6.1 27e34098d3 fix(ui): size the font field for the localized mixed label
Measure Mixed with the active body font and include the input margins and caret allowance. Keep that minimum stable while typing so the full label is visible without shifting the row on each keystroke.

A themed panel regression fails against the old 40-pixel input, verifies the text fits inside the field margins and keeps the alignment control inside a 272-pixel pane. Linux scoped clippy, format tests, wasm, formatting, layering and assets pass.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
2026-11-01 16:34:38 +01:00
FredAppsandCodex GPT-6.1 a3840e1eda fix(ui): paste delivered images instead of guessing from key releases
The pinned integration consumes native clipboard shortcut keys and delivers PasteImage pixels. Handle those payloads in order, keep text cache invalidation, and use the delivered image even if the OS clipboard changes before processing. Preserve alpha and validate dimensions and byte counts before allocation.

Remove release timestamps so Windows clipboard history cannot reuse a completed paste gesture. Keep explicit shortcut fallback for control-channel and browser internal-image paste, with modal, focus and permission guards unchanged. Tests cover both release orderings, history after prior paste, mixed batches and duplicate prevention.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
2026-11-01 16:30:06 +01:00
FredAppsandCodex GPT-6.1 b7d04009a2 fix(ui): refresh font-size text when selection becomes mixed
Include the mixed-size flag in the font-size draft cache key. Selecting a mixed block can preserve the previous representative number, so a value-only key left the field showing 24 instead of Mixed. Unchanged formatting still preserves partially typed input across frames.

The headless regression covers uniform-to-mixed and mixed-to-uniform transitions with the same number, draft preservation and a single committed edit. Linux scoped clippy, tests, wasm, formatting, layering and assets pass; reverting the cache fix reproduces the stale display.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
2026-11-01 16:18:26 +01:00
FredAppsandCodex GPT-6.1 e7762568cc docs(text): define mixed-script normalization and undo policy
Document the existing policy: mixed plain and target-script text normalizes to that script, then to plain text, rather than reconstructing the original mixture. Undo restores exact prior text. Cover both scripts in engine and headless tool tests, including document-byte restoration, redo and save/reopen, and record the evidence in parity. The new tests pass against unchanged conversion logic; this is policy documentation and coverage, not a product behavior fix. Scoped Linux native, wasm, clippy, formatting, layers, assets and parity validation passed.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
2026-11-01 16:12:39 +01:00
Grzegorz MartensandClaude Opus 5.5 4303d49eea M2: a reference to a reference is what it names
`IndirectObject<f32>` read an object holding `6 0 R` as the number 6, so `/Decode [11 0 R 0]`, with
11 naming 6 and 6 holding 1, read as 6, and `/W` gave glyphs such widths. As anything but a number,
such an object was lost.

`XRef::get_with` is how every reference is read, to an object stored on its own or in an object
stream, so it now follows such objects in a loop, up to 32 references as `Document::resolve` does in
#5548. A loop takes no stack however long the chain, and a cycle runs out of references and reads as
a missing object, as a reference to nothing does: the image with such a `/Decode` isn't drawn, as
with `/Decode [99 0 R 0]`.

An object stream isn't reached that way: it has to be a stream stored as that object, and following
a reference to one stored inside another let a 1 KB file run out of stack. `XRef::objects` leaves
such objects out, or a page came out once more for each one holding a reference to it, and a comment
inside a reference counts as white space, as it does everywhere else.

Reading an object stream's index now counts against the 64 nested loads, and reads its dictionary
alone. That is older than this branch, which only made it slightly worse: a chain of object streams,
each with a member of the next for its `/N`, `/First` or `/Length`, recursed with no limit, holding a
copy of the chain at each, and aborted on 750 KB with an 8 MiB stack, or 250 KB with 2 MiB, in a test
build. Parsing the stream read `/Length` as well as `/N`, two ways to the next stream's index, and a
failed index isn't remembered, so the work doubled at each stream: 20 streams in a ring took 20 s on
`main`. ISO 32000-2 7.5.7 keeps an object stream's `/Length` out of object streams, so no legal file
has a `/Length` chain. Nothing forbids `/N` or `/First` by reference, though no writer I know of makes
such a chain. Past the limit it reads as missing unless a stream within 64 of it has been read.

`/W` and `/W2` with their list by reference are tested too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
2026-11-01 15:28:31 +01:00
FredAppsandCodex GPT-6.1 73655948c6 fix(automation): flip images along displayed page axes
Map horizontal and vertical tool actions to PDF user-space axes after accounting for page rotation. The tool description states the displayed-coordinate semantics. A four-quadrant raster and transformed-corner regression covers both actions at 0, 90, 180 and 270 degrees, with undo between actions; it fails on the wrong axes before this fix. Scoped automation clippy, all 354 tests, wasm, formatting, layers and assets pass on GGEO-AI02.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
2026-11-01 15:05:32 +01:00
FredAppsandCodex GPT-6.1 0b0d39c661 docs(edit): record PR 2155 review follow-ups
Record image crop and stream ownership, visible orientation, clipboard and formatting fixes, Home controls, and reloadable font discovery as PR candidates. Estimates remain unchanged.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
2026-11-01 15:01:00 +01:00
FredAppsandCodex GPT-6.1 0595d4d397 fix(ui): preserve author clips and route crop controls before page content
Offer Remove Crop only for editor-owned clips, reset draft cropping to the author-visible bounds, and remove only an owned crop when confirming the full image. Active crop mode owns presses on its page so underlying text and marquee selection cannot steal crop controls. Label the painted controls for accessibility and automation.

The author-clip regression opens the real menu, resets a draft crop and confirms it while preserving the authored clip. It failed before ownership checks and again before the router fix.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
2026-11-01 14:58:21 +01:00
FredAppsandCodex GPT-6.1 d423dd03ec fix(ui): keep image grips and flips aligned with the visible page
Use matrix resizing whenever image axes are turned or reflected on screen, including document and view rotation. Share the visible grip geometry for cursor claims and hit routing, and use only the drawn rotate knob. Map flip labels to the visible axis and defer Cut selection clearing to its result.

Regressions cover all page/view rotation combinations and 64 outward drags across every grip, asserting fixed anchors and pointer tracking for upright and rotated images.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
2026-11-01 14:58:21 +01:00
FredAppsandCodex GPT-6.1 0046177f47 fix(engine): validate image transforms and promote arbitrary added-image transforms
Reject finite but singular or overflowing determinants at the engine boundary. Promote added images for arbitrary transforms, as RotateBy already does, while preserving editable quarter turns and reflections. Regressions verify transformed placement, promotion, undo and refusal without mutation.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
2026-11-01 14:58:20 +01:00
Grzegorz MartensandClaude Opus 5.5 1b61121c66 M2.6: a page's forms and pictures read their resources in place
Each `Do` copied the page's `/XObject` dictionary, and each form its `/Resources`, `/Properties`,
`/Font` and `/ExtGState`, or the resources it was drawn with if it had none. So Office export of one
page took time in the square of what it drew: 31 s for 10,000 pictures, about 70 ms of it decoding, 30
s for 10,000 forms with no `/Resources`, and 16 minutes for one form with 100,000 keys in them drawn
50,000 times, in a test build.

`FormCall` keeps the form and `resource_dict` reads a dictionary where it is, with an object of its
own held. 10,000 pictures take about 0.15 s now, 10,000 forms 79 ms, and that form drawn 5,000 times 40 ms. The test holds to 10,000 pictures, not the 2,000 it could afford.

A `gs` reads a direct graphics state in place too, in the text walk and in `page_background`, and a
value of the wrong type isn't copied to find that out. A form that sets a font still reads the font each time it is drawn, as the fonts read
are kept only for that draw: 3.5 ms a draw for one of 100,000 widths.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
2026-11-01 14:53:48 +01:00
FredAppsandCodex GPT-6.1 aa68d0c27f fix(home): show pinned tools once and expose unpin controls
Omit pinned tools from Recommended and keep unpin buttons in the accessibility tree without requiring pointer hover.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
2026-11-01 14:51:28 +01:00
FredAppsandCodex GPT-6.1 faf85f5af9 fix(text): apply explicit sizes and preserve script characters
An explicit size commit normalizes mixed-size selections even when the value matches the displayed size. Caret-only script commands format the whole draft. Mathematical minus uses reversible Unicode forms and ASCII hyphen-minus remains unchanged. Correct the applied-selection comment and document the character policy in parity and the tool.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
2026-11-01 14:51:27 +01:00
FredAppsandCodex GPT-6.1 a310d5a41a fix(ui): respect clipboard authority and retain refused cut selections
Do not reuse stale native images for unsupported clipboard contents, while preserving web internal image paste. Observe text paste before focus gating and keep image-less key releases silent. Tie release fallback to V gestures. Check modification permission before copying and clear selection only after successful deletion.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
2026-11-01 14:51:27 +01:00
FredAppsandCodex GPT-6.1 36a6a572b8 fix(engine): match added images by their owning stream
An original image and an added item may share an XObject without sharing editable metadata. Require the selected drawing stream to own the added item instead of falling back to any matching resource. The regression actually moved the added sibling before the fix; scoped native and wasm gates now pass.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
2026-11-01 14:47:46 +01:00
FredAppsandCodex GPT-6.1 9a1334e04d fix(edit): preserve image scopes and content ownership
Move editor crop scopes with grouped images while retaining fixed author clips and folding repeated transforms. Arrange keeps relocated original artwork in its own stream beside an added item, so later edits or deletion cannot discard it; unusual shared owned streams are refused. Refuse nested marked-content extraction when its tags cannot be preserved. Synthetic regressions and the headless group-move, undo/redo, save/reopen, arrange, delete and render lifecycle fail before these fixes and pass afterward.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
2026-11-01 14:47:46 +01:00
FredAppsandCodex GPT-6.1 3a0ea63c33 fix(edit): share saved drawing operands across graphics scopes
Keep dash, color and extended printing operand payloads shared across q snapshots. Copy-on-write color updates preserve saved values without multiplying large operand arrays by nesting depth. A pointer-sharing regression failed before the change; scoped native tests, clippy and wasm check pass on GGEO-AI02.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
2026-11-01 14:47:46 +01:00
FredAppsandCodex GPT-6.1 43ad4bf418 feat(edit): expose image crop ownership to frontends
Report active PdfCraft crop markers through PageImage::has_editor_crop and page_images.has_editor_crop so frontends can distinguish removable editor crops from author clipping paths.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
2026-11-01 14:47:46 +01:00