data-host="page" on the canvas opts a page that loads the module into its own document into the host bridge. The ?host=parent messages travel as non-bubbling CustomEvents on the canvas; host::Bridge holds a Transport (Parent or Page) with one send, and save, dirty, ready and failure reporting are shared. ?host=parent is checked first and unchanged. Hosting guide documents it.
* M1: respect generations in COS object references and full saves
Resolve stale references to null instead of replacement objects with the
same number. Validate complete identities in writer readers, indirect
stream lengths and catalog checks, and keep generation-aware length caches.
Cover cache reuse, edit overlays, snapshots, incremental and packed/classic
full saves, and stream lengths with synthetic regressions and independent
hayro checks.
Co-Authored-By: Codex <noreply@openai.com>
* M0: clarify refreshed CI roadmap note
Co-authored-by: OpenAI Codex <noreply@openai.com>
* M1: repair contradictory xref generation references
Address maintainer feedback on the existing PR. Preserve upstream work and document the tested scope and remaining validation limits.
* M1: cover repaired generations and freed-slot round trips
Address maintainer feedback on the existing PR. Preserve upstream work and document tested scope and validation limits.
* M1: document generation repair and bounded diagnostics
Address maintainer feedback on the existing PR. Preserve upstream work and document tested scope and validation limits.
* M1: record generation repair regression evidence
Address maintainer feedback on the existing PR. Preserve upstream work and document tested scope and validation limits.
* M1: document bounded COS generation repair
Address maintainer feedback on the existing PR. Preserve upstream work and document tested scope and validation limits.
* M1: record generation repair parity evidence
Address maintainer feedback on the existing PR. Preserve upstream work and document tested scope and validation limits.
* fix(cos): preserve repaired generations through preflight and saves
Keep accepted xref/header aliases across repair-aware edits and snapshots, canonicalize full-save identities, and retain bounded generation diagnostics from older revisions. Add COS, writer/encryption, and real preflight regression coverage.
* test(preflight): assert repaired aliases share saved identity
Address the review nitpick by comparing reopened HeaderImage and RowImage references after damaged full saves, for classic/packed output and edited/restored snapshots. Focused preflight regression and rustfmt check pass.
* M14: update certificate dependencies for RustSec advisories
Bump rustls-webpki to0.103.16 and webpki-root-certs to1.0.10. Preserve all other locked packages and dependency lists, manifests, Git pins, and advisory policy.
---------
Co-authored-by: MMexicann <MMexicann@users.noreply.github.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: FredApps <FredApps@users.noreply.github.com>
CodeRabbit's findings on #6243, each checked against the code:
- A double-click on the objects selected together took its target from
the hits at the release, so a release just off the paragraph pressed
opened nothing. The router keeps what lay on top at the press with the
objects aside (`under_objects`), as every owner acts where its press was.
- A drag first seen on another page left the picked picture picked: that
page is told `Elsewhere`, and the picture's test no longer ran there.
- Delete with a button held removed the item, and the press held then named
the next one. Delete waits for the button to come up, for pictures and
added content.
- A page just off the screen is still run for what lies near it, so a
picture's keys acted there unseen. They ask whether the page is on screen.
- Add text's drags end while its input is blocked, as Edit text's do.
- With the page gaps hidden, a Shift-click on the row two pages share
selected on the first page and the second cleared it. A press another
page holds leaves the selection alone.
Tests, each seen failing with its fix reverted:
`a_double_click_on_a_grouped_paragraph_released_just_off_it_opens_it`,
`a_drag_first_seen_on_the_next_page_lets_the_picked_picture_go`,
`delete_waits_for_the_button_to_come_up` (each half),
`a_selected_pictures_keys_wait_for_its_page_to_be_on_screen` (its
continuous case), `a_paragraph_drag_ends_when_the_window_loses_focus` (Add
text), `a_shift_click_where_two_pages_touch_keeps_what_it_selected`,
`a_press_counts_the_modifiers_of_its_own_event`.
`add_text_keeps_a_changed_paragraph_and_a_draft_when_it_moves_on` pins that a
click on the page applies the open paragraph before a new box starts, so
neither edit can take the other's place; seen failing with the draft's edit
dropped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ui): About credits tables fit without side-scrolling and their columns resize
The Contributors table and the Models table were egui Grids inside a
two-way scroll area: they opened wider than the dialog, so they scrolled
sideways, and Company and Model sat almost touching. Both are now
egui_extras tables. Each column opens at the width of its header and widest
cell, the spare width goes to the text columns (Name; Company and Model),
and every column edge can be dragged. Widening a column grows the table
like a spreadsheet, and only then does it scroll sideways; the header stays
put while the rows scroll. Counts and dates are right-aligned and every
cell is vertically centred.
The sorted column stays highlighted and its direction shows on the
toolbar's sort-order button, so headers no longer reserve room for an
arrow. The opening widths come from fit_widths, a pure function with unit
tests that a fitted table fills its room exactly and that only the text
columns give way when room is short.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Let every credits column be dragged, and refit changed tables
The last column was egui's remainder column, which has no drag handle, so
it could only be resized from the edge before it. It is now an ordinary
column with its own handle.
A table keeps its column widths, so switching to a longer name left the
Name column at its old width and clipped the text. The table now goes
back to the opening fit whenever that fit changes: a longer widest cell
or a resized window. Dragged widths are dropped at that point.
fit_widths could overflow the room when one column hit the minimum,
because the other columns did not take up its share. Columns now give
way in proportion to their width above the minimum.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Refit credits tables on what they measure, not the fitted widths
Comparing the fitted widths missed the case it was meant for. Name is the
only growing column, so a longer name takes its extra width from the
spare room and the fit comes out the same: a dragged Name width stayed,
clipping the longer name.
It could also drop dragged widths by accident. The fit comes from the
available width inside the scroll area, which scrolling can nudge, so
scrolling a widened table could reset it.
The table now compares the natural widths and the clip rect's width,
which scrolling does not move.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Keeps main's reworded mono-image text and the target_bytes paragraph in the doc_optimize description.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Upstream now counts the parsed tree and keys in held_bytes and tracks the cache total itself,
which replaces this branch's copy of the cache accounting and its owned_bytes. write_full's
retention budget uses held_bytes; the separate node budget is dropped since held_bytes counts nodes.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
pa-Arab-PK is Punjabi in Arabic script, which Word keeps as right-to-left
text, but word_lang looked only at the language and wrote w:val. A script
subtag (Arab, Hebr, Syrc, Thaa; Hans, Hant, Hani, Jpan, Kore, Hang, Hira,
Kana; Latn, Cyrl, Grek) now decides over the language. It is read only in
its own place, after the language and any extended languages, so private
use such as en-x-arab names no script.
A singleton (one letter or digit) starts an extension, or with x private
use, and BCP 47 needs a subtag after it. en-x and en-a were written as the
document's language. They and a singleton straight after another are now
left out; one-character subtags inside private use stay allowed.
BCP 47 sets no maximum length; 35 characters is only the least a protocol
must hold. A well formed tag such as en-US-u-ca-gregory-nu-latn-co-phonebk
was left out of both exports. The bound is now 255, kept only so a PDF's
/Lang can't put an unbounded string in the file.
Word export named no language, so Word checked the spelling of every
export as English and underlined a whole document in any other
language. The PDF already says its language in the catalog's /Lang.
When that is a well formed language tag, Word gets it as the default
language of the text (w:docDefaults), in the attribute Word keeps for
its script: w:eastAsia for Chinese, Japanese and Korean, w:bidi for
Arabic, Hebrew, Persian and Urdu, w:val for the rest. Both HTML
exports, with and without CSS, get <html lang>. Without /Lang, or with a
malformed one, the files are exactly as before.
docx_with_language, html_with_language and html_simple_with_language
take the language; docx, html and html_simple stay as they are and call
them with none. The engine reads /Lang through the existing initial
view.
The new export and engine tests fail without the change.
Review fixes for Copy with formatting.
- ui-egui: the HTML copy goes through one arboard Clipboard, created on
first use and kept in the app (os_clipboard::with_kept, under the same
process-wide lock), instead of a fresh one per copy. On X11 the copied
data is served only while its Clipboard lives, so a fresh one dropped
at once could leave nothing to paste without a clipboard manager. A
failed create or set falls back to egui's plain-text copy.
- ui-egui: html_clipboard_override stands in for the system clipboard in
tests. With the system clipboard on, Copy sets HTML and plain text in
one set and emits no CopyText; when the set is refused it emits
CopyText with the plain text. The HTML is built only when a clipboard
will take it (system clipboard on, not the web build). The
last_copied_html field is gone.
- export: clipboard HTML text is escaped in one pass and also drops C1
controls, a bare carriage return and the bidirectional overrides and
isolates. Font sizes are written within 1 to 1000 pt.
- engine: the glyph-to-block step budget is a parameter, tested; the copy
says styles_incomplete only when matching actually ran out of steps.
- automation: text_extract format "html" has one 32 MiB HTML budget
across all pages; a page past it gets none, and the result carries
html_truncated. The tool description says so.
- parity: the new tests are evidence.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SqmHYx8FiWM5PcsoiErgp9
main's 3D-embed change (#5808) added crates/annot/src/threed.rs with its own
pub MAX_MODEL_BYTES (same 256 MiB value), so both were re-exported from the
crate root and pdfcraft-annot no longer compiled after merging main. model3d
now uses threed's constant.
Found in review: the PR lists these and nothing pinned them.
- With Prepare open, a drag from a highlight draws the selection rectangle.
- A double-click on a paragraph selected with others opens it.
- In crop mode, a right-click on the next page goes to what lies there,
though a clipped artwork's whole frame reaches over it.
- A crop grip takes a press within its reach, 9 px off.
- A comment's menu opens over a picture and over a paragraph.
- A right-click with the button held opens the selected comment's menu.
Each seen failing against a planted violation.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found in review. No change in behaviour.
- The guard's `PAGE_HIT_CALLS` refused nothing once `main`'s press-handler
check went; it only failed when it was stale, so it goes.
- The guard's notes said `canvas/image_pick.rs` uses none of the marks (it
takes `PagePointer` now), that page modules read only
`PagePointer::drag_started` (some ask for the primary button themselves),
and left out the point tests that tell a tool a press began on its page.
- `content_ui`'s and the comments' notes said added text is its own with
every tool, and that added content decides for itself.
- `object_ui`'s `!double_clicked()` can't fail (the page view re-routes
that press), and Fill & Sign's preview recomputed `hovered`.
- `Capture` is private, and `top` is `canvas`'s.
- Test notes gave as history bugs that only this branch ever had.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found in review. `fix(ui): a right-button drag on the pages starts nothing
a left one does` covered drag starts. A right-button drag still moved the
end of a selection already made, as `update_dragged_selection` tested a
drag by any button (`main` replaced the selection instead). And its end
finished a selection whichever button it was, so with a markup tool, Replace
Text or Redact a selection left from another tool became a comment. Both
read the primary button now.
Tests, each seen failing with its fix reverted (Redact's on its own):
`a_right_button_drag_leaves_a_text_selection_alone`,
`a_right_button_drag_makes_no_mark_of_a_text_selection`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found in review, each against `main`:
- With Add text holding text it can't draw, a drag from a paragraph moved
the paragraph; only its click was refused. Neither acts now (#125's
draft stays where it is being typed).
- A right-click reached a Prepare field whatever the field tool and while
a table is set up (a review ruling), but also on a document that can't
be changed, where Prepare stays open after a tab switch: it selected the
field and opened a menu of entries the engine would refuse. It selects
nothing there.
Tests, each seen failing with its fix reverted:
`add_text_moves_no_paragraph_while_it_holds_a_draft_it_cant_draw`,
`with_prepare_on_a_locked_document_a_right_click_on_a_field_selects_nothing`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found in review. On `main` the selected picture's grips and rotate knob
were drag-only widgets of their own, so their drag began at the press.
Their widgets went, and the page's response is click-and-drag, which calls
it a drag only past egui's click distance: a move of a few pixels resized
nothing. They take their drag from the press again. A click that doesn't
move edits nothing, as before; a drag of the picture itself still waits,
since a click selects.
Tests: `a_short_drag_from_a_picture_grip_resizes_it` (seen failing with
the fix reverted), `a_click_on_a_picture_grip_changes_nothing` (a pin,
seen failing with the release planted to edit always).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found in review. The selected picture's frame is its own on `main`: a
drag from it moves it, though another picture lies over it there. The
routed press was the top picture's, and the drag only started for the
selected one's, so nothing moved. `PicturePart::OverSelected` says so: a
click there selects the picture on top, as before, and a drag moves the
selected one.
Test, seen failing with the part planted away:
`a_drag_from_the_selected_picture_under_another_moves_the_selected_one`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found in review. Delete, Backspace and crop's Enter and Escape moved to
the app's keys, which run before anything is drawn and don't look at what
is on screen. So with Edit text and a picture selected:
- Delete in the page grid removed the hidden picture and kept the pages;
- Delete with the pointer on the Pages panel did the same;
- with the picture's page scrolled away or in single-page view on another
page, Delete removed a picture the reader couldn't see, and Enter
applied its crop.
`main` read these keys in the picture's own page pass, which none of
those cases reach. `picture_keys` runs there again, from
`page_tool_input`, under Edit text's gate (so no dialog gets them), and
before the group acts. Delete still works wherever on the pages the
pointer is.
Tests, each seen failing with the fix reverted:
`delete_in_the_page_grid_deletes_the_page_and_not_the_hidden_picture`,
`a_selected_pictures_keys_wait_for_its_page_to_be_on_screen`,
`delete_with_the_pointer_on_the_pages_panel_deletes_a_page`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found in review. With Edit text, a right-click on added text or on an
open paragraph's frame went to that, which has no menu: the picture under
it was unselected and the page's menu opened. `main` opens the picture's.
Those give way to a picture under them, as paragraphs do, and to nothing
else: a comment under added text stays unselected, as before.
A comment in `draw_pages` said a selected Prepare field keeps its menu
off the pages. Since the page menu follows the right-click, it stays
selected and the menu is the page's.
Tests, each seen failing with the fix reverted:
`a_right_click_on_added_text_over_a_picture_selects_the_picture`,
`a_right_click_on_an_open_paragraphs_frame_over_a_picture_selects_the_picture`.
`a_right_click_with_edit_text_on_added_text_over_a_comment_selects_no_comment`
is a pin, seen failing with added text dropped from the hits outright.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found in review:
- Rule (f) missed `pub(in …)` functions, the visibility the guard's commit brought
in (`declares` strips any `pub(…)`), and flagged names that merely
end in its words (`dropdowns`): it now matches whole words of the name.
- Inside `canvas` the narrowed visibility doesn't hold, and a router
taken whole (`let r = &view.router;`) got past the checks by method
name; such a use now counts as the router's (`takes_the_router`).
- Docs: the router's module doc and `PagePress::Free` say a declined
drag is nobody's once it starts; Prepare's note says a highlight's drag
is Prepare's; Add text's paragraph note names `ParagraphCx::adding`;
a test's doc claimed crop-mode keys it doesn't press.
- One source each for the objects' menu test (`object_ui::menu_open`)
and Edit text's gesture cancel (`cancel_pointer_gestures` calls
`cancel_edit_text_gestures`); the page-menu test asserts an entry
only the page's menu has.
Each guard addition seen failing against a violation planted in
`#[cfg(any())]` code in `canvas/area.rs`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found in review, each against `main`'s behaviour:
- A double-click on one of the objects selected together only left the
group: the second press was the group's. It is the object's under it,
so added text opens for typing and a picture is selected, as before;
a paragraph opens too (the user's ruling).
- On a page whose objects can't be selected together, a click on the
empty page left the picture selected: no area selection starts there
to drop it, and the picture's own test that did is gone. A click nobody
holds on the page unselects it.
- Crop mode's grips stopped at the page's edge, so those of a picture
filling its page could be taken from their inner half only. They reach
past it, cursor, press and right-click: no page took a right-click
there, which left crop mode and opened the page menu (#5900 keeps crop
mode there). The box and the picture stop at the page's edge, as a
clipped artwork's whole frame can reach over the next pages.
- A press past a page's edge was the page's whenever it had any hit
there: the objects selected together, or the open paragraph's frame,
took presses on the next page and did nothing with them. Past the edge
only the selected picture's knob and grips (crop mode's too) take a
press, and the objects' hit stays on its page.
- A drag from a hole in the selected picture (a clip with a hole) fell
through, started an area selection and unselected it. The selected
picture's frame is its own, as before.
- Image pick: a drag or double-click from a link let the picked picture
go before ruling 5, and does again; the link's click still picks none.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`refactor(ui): crop mode is a hit of its picture` moved the picture's Delete to the app's key handling, which
runs before the page view, so its edit applied before added content read
the keys. Added content's selection mirrors the picture's when the
picture is added content (`sync_image_selection`), and once the picture
was gone that index named the next added item on the page: added
content's own Delete, seeing the same key press, deleted it too.
The picture's Delete consumes the key, and drops the mirrored selection
with the picture's.
Found in review.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found in review of the right-clicks 4b routes:
- With Edit text, a right-click on a picture under a link went to the
link, which Edit text doesn't follow: the page menu opened and the
picture was unselected. A right-click counts links only for the tools
that reach them (Select; the Link tool).
- Edit text's paragraphs have no menu, and give way to the picture
under them (the user's ruling): text over a picture, an OCR'd scan's
among it, no longer hides the picture's menu.
- With a Prepare field tool, or while a table is set up, Prepare's hit
leaves fields out, so a right-click on the selected field opened the
page menu. A right-click reaches fields whatever the field tool.
- In crop mode, a right-click off the crop went to crop mode's whole-page
hit and unselected every picture. Only one on the picture being
cropped, its box or its grips is the crop's (#5900's area), which
opens no menu; elsewhere it goes to what lies there, as without crop
mode: another picture is selected for its menu.
- Under a held press, the menu was the page's on anything but a link. It
is the routed owner's when that owner is the one selected (the held
press leaves the selections alone), the page's otherwise.
`DocView.menu_for` is `pub(in crate::canvas)`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`fix(ui): a comment's move, resize or reshape ends` ended a comment's move, resize or reshape once the button was
up, and applied it where the pointer then was: when the pages missed
the release (the page scrolled out of range, a tab switch, a tool
switched mid-drag), the comment jumped to wherever the pointer next
showed up over its page, and while the pointer stayed off the pages the
gesture waited for it.
Only a drag that stops on the page applies its gesture now; one that
ends with the button up and no drag stopped there ends with nothing
applied, whether the pointer is on the page or not. The test hovers away
from the move's start, where the jump shows.
Found in review.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The pages' presses are the primary button's (`PagePointer.edges`, the
router's `began`), so a right-button drag was a press nobody held, and
every tool that started on egui's `drag_started()`, which counts every
button, started on it: the Rectangle tool drew a rectangle, Prepare's
selection rectangle selected the fields in it, the Link tool opened Link
Properties for a new link, the camera moved its quadrilateral to the page,
and the Select tool selected text. On `main` too.
`PagePointer.drag_started` is a primary drag of a press the pages hold,
started this frame. The page modules read it instead of egui's (comments'
shapes, callout and text box, Prepare, the Link tool, the camera, the text
layer, image pick, and the Edit text group, whose owned presses were
primary already); zoom, crop, Sign area and Redact already asked for the
primary button. The guard refuses a bare `.drag_started()` in a page
module (`NOT_PAGE_DRAGS` lists the widgets of their own: Organize's
thumbnails, the signature pad, the Scan tab), and the router's
`drag_started` is `drag_began`, so the rule reads cleanly.
Tests, one per family, each seen failing with the fix reverted:
`a_right_button_drag_draws_no_rectangle`, `…_selects_no_field`,
`…_draws_no_link`, `…_leaves_the_camera_quadrilateral`,
`…_selects_no_text`; the guard rule against a planted `#[cfg(any())]`
call.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
It hovered fifty times with a 10 ms sleep between, so a busy runner
could run out of tries before the page's text or paragraph boxes
arrived from their worker threads. It now steps frames with
`support::step_until`, as the other waits for background work do,
until the cursor is the one wanted or 30 seconds pass.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With the Edit text group, the text layer and link following told what
the press is to their page, only the page view reads the router.
- The router's methods and `DocView.router` are `pub(in crate::canvas)`:
outside `canvas` the compiler refuses a read or a write, aliases
included, which the guard's text match could miss. `ROUTER_READERS`
keeps only the page view's dispatcher (`page_tool_input`).
- Rule (f): no function in a page module is named with "grabs" or
"owns", which decide for themselves whether a press is theirs.
- CLAUDE.md's "Page presses" rule says so: modules never read the
router; they are told.
Each rule seen failing against a violation planted in `#[cfg(any())]`
code (a `router.keeps_drag()` read in `content_ui`, a `fn fill_grabs` in
`fill_sign`), and a real router read from `content_ui` no longer
compiles.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A comment's gesture ended only on egui's `drag_stopped()`. When the pages
missed its release (the button let go where they didn't see it), the
gesture stayed live: it kept the page's frames from Fill & Sign and the
shape tools, and the next drag that stopped on the page committed it,
taking the comment there.
It now ends, as the other page gestures do, on `drag_stopped()` or once
the primary button is up, where the pointer is.
Two tests planted a live move with the button up to check that a live
move keeps its page's presses (`main`'s
`active_comment_gesture_keeps_highlighted_link_click` and 4a's
`a_fill_and_sign_click_places_nothing_while_a_mark_is_moved`). That
state now ends at once, so both hold the press through the planted move
instead: the intent stands, and each still fails with the live-move
guard taken out.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The text layer asked the router whether the press's owner kept its drag,
link following asked it which link held the press, and the Link tool
started a new link from a press any link held, since the router kept a
declined drag's capture.
- `PageRouter::drag_started`: a drag the owner declines (text markup;
with the Link tool, a link) is nobody's once it starts, on the page it
began on. The Link tool draws a new link only from a drag nobody
holds.
- `PageInput` carries the press (`PagePress`) and whether its drag is the
page's text's (`text_drag`): the text layer and link following read
them, and `PageRouter::owner` goes. Only the page view reads the
router now.
- Image pick acts on a press nobody holds: a link's click follows the
link only, and picks no picture under it (the user's ruling).
- The I-beam drops over a link only where a press would go to it, the
top hit under the pointer (the user's ruling): the tools that select a
link's text show it there.
- `PageText::glyph_at` is the one test for the text under a point, for
the text layer and Redact's boxes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Edit text ignores input while a dialog, the palette, another window or
another tab has it. Only a drag of the objects selected together ended
then; a paragraph's move or rewrap, a picture's move, resize, turn or
crop and added content's move waited, and once the input came back with
the button up they landed wherever the pointer was.
While Edit text's input is blocked, `DocView::cancel_edit_text_gestures`
abandons them all, as the objects' already was.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>