Commit Graph
1749 Commits
Author SHA1 Message Date
Codex b5fad8e858 Use mutable subpath iteration for current Clippy 2026-11-12 19:45:08 +01:00
FredApps 17b74601fb Merge pull request #2663 from dotCooCoo/feat/alpha-channel-text-wrap
Text Wrap: Alpha Channel contours follow a transparent image's visible pixels
2026-11-12 19:38:50 +01:00
dotCooCoo d9afe26fc8 Merge main into feat/type-shortcuts-carry 2026-11-12 10:10:51 -08:00
FredApps 2348380198 Merge main and preserve PR #2663 behavior 2026-11-12 18:14:28 +01:00
Codex 7f8b352196 Merge main and retain shortcut and preflight documentation 2026-11-12 18:13:30 +01:00
Codex e81b2ea99e Merge main and preserve table query options and ID guidance 2026-11-12 18:13:30 +01:00
FredApps a5be0905dd Merge pull request #2649 from dotCooCoo/fix/merge-image-fields
Data merge: an image field in text places the image, not its path
2026-11-12 18:05:02 +01:00
FredApps 9aa103b3a8 Merge pull request #1843 from dotCooCoo/fix/copied-story-anchor-table-ids
Copy: copied text gets text anchors and tables of its own
2026-11-12 18:04:28 +01:00
dotCooCoo 49792c9ad5 Text wrap: look up Alpha Channel outlines by binary search
The document keeps its outlines sorted by image and threshold, and the
lookup uses a binary search. The data merge test now checks that the
merged document has the image's outline, and that a bounding box wrap
leaves the same caption overset.
2026-11-12 09:04:11 -08:00
FredApps 31d4c7f7f4 Merge pull request #2665 from dotCooCoo/feat/paste-clipboard-image
Paste: images on the system clipboard paste as embedded images
2026-11-12 18:03:55 +01:00
FredApps e8276337a3 Merge pull request #2354 from dotCooCoo/fix/table-story-target
Reject ambiguous table IDs across stories
2026-11-12 18:02:30 +01:00
FredApps 6e50ee3974 Merge pull request #2650 from dotCooCoo/feat/paragraph-value-checks
Text: paragraph spacing and justification values are checked
2026-11-12 17:57:35 +01:00
FredApps 2522b78ef3 Merge pull request #2656 from dotCooCoo/fix/preflight-off-interface-thread
Preflight: check the document on a background worker, not on every edit
2026-11-12 17:56:38 +01:00
dotCooCoo 7604db695f Copy: point copied cross-references at copied anchors in one pass
Each copied story with text anchors walked every story copied before it
to retarget their cross-references, so copying many such frames took
time quadratic in their number. The copies' cross-references are now
pointed at the copied anchors once, after the last item is copied.
2026-11-12 07:57:27 -08:00
dotCooCoo 329806477e Data merge: an explicit QR role in text is refused, and the caret follows each field
data.placeholder.add with role qr and the insertion point in text bound
the QR code to the first selected frame, which the caret was not in. It
now returns "qr placeholders bind to a frame", as a QR field there does.

A field inserted at the insertion point left the caret before its
marker, so a second field went in front of the first. The caret now
moves past the marker, as after typing.

Docs: docs/agents.md.
2026-11-12 07:45:10 -08:00
dotCooCoo c2a1543528 Copy: mark the renumber results as must-use
renumber and its helpers return false when a copy nests deeper than
MAX_COPY_DEPTH and must not be inserted. They now carry #[must_use], so
a caller that drops the result fails to build under -D warnings.
2026-11-12 07:40:29 -08:00
Adithya Shankaran 92043b4c48 Automation roots: refuse COM¹ to LPT³ and a device name before a colon (#2383)
* Automation roots: refuse COM¹ to LPT³ and a device name before a colon

is_device_name missed COM¹, COM², COM³ and LPT¹, LPT², LPT³, which Windows reserves as it does COM1.
It also cut the name only at a period, so COM1: and NUL:x were not seen as device names.

* Credit my name in the About window

* Automation roots: document the device-name tests

CodeRabbit's docstring check counts the touched tests. same_component stays without a doc comment, because #2205 deletes that function and a doc line above it conflicts.

* Automation roots: record the device-name refusal

The MCP roots description and the roadmap now name COM¹ to LPT³ and a device name before a colon.
2026-11-12 15:09:39 +00:00
dotCooCoo fad00dd646 Data merge: an image field in a table cell or a note is refused by name
With the insertion point in a table cell or a note, data.placeholder.add
with an image field returned "a hyperlink field can't go in a table cell
or a note". It now returns a message about image fields that names the
two ways on: bind the field to a frame, or pass role text to merge its
path. Nothing is inserted on the error, and role text still puts the
marker in the cell.

Docs: docs/agents.md and the command's params text.
2026-11-12 05:58:02 -08:00
dotCooCoo 375a7b48b1 Merge main into fix/merge-image-fields
# Conflicts:
#	crates/engine/src/cmd/datamerge.rs
2026-11-12 05:21:21 -08:00
autocraft-bot[bot] 3205b634dc Merge main into feat/alpha-channel-text-wrap 2026-11-12 12:08:38 +00:00
autocraft-bot[bot] 54294ef791 Merge main into feat/alpha-channel-text-wrap 2026-11-12 11:38:19 +00:00
autocraft-bot[bot] 424d08d935 Merge main into fix/datamerge-fields-in-tables 2026-11-12 11:38:19 +00:00
Dylan M. Taylor 027bbae9cb Engine: index style, tag, swatch and run lookups; bound polygon sides, Change All and spelling candidates
* fix(engine): index lookups that were quadratic in a document's styles, tags, swatches and runs

* address review: first swatch per name in book sync; bound spelling input before collecting

* address review: keep the last source style per name in book sync; bound GREP replacement bytes while generating them

* address review: write GREP replacements into a byte-bounded buffer; gate keep_last test off wasm

* merge main into fix/sec-engine-linear-lookups

* address review: make the suggestion length-cap test deterministic
2026-11-12 06:28:15 -05:00
Dylan M. Taylorandautocraft-bot[bot] ff0463e299 Exports: leave out text the page doesn't show (inherited conditions, deletions, hidden layers)
* fix(export): leave out text hidden by inherited conditions or deletion in every exporter

* address review: skip hidden frames in page text and hidden article items; first visible paragraph as nav label; read table anchor's own format

* address review: skip nonprinting frames and non-printable layers in fixed-layout page text

* Apply review fixes

- crates/epub/src/html.rs
- crates/engine/src/cmd/export/formats.rs

* Apply review fixes

- crates/epub/src/html.rs
- crates/engine/src/cmd/export/formats.rs

* address review: fixed-layout page text skips frames in inactive object states

* address review: place a threaded story at its first shown frame; skip it only when every frame is hidden

---------

Co-authored-by: autocraft-bot[bot] <354215646+autocraft-bot[bot]@users.noreply.github.com>
2026-11-12 06:28:07 -05:00
Dylan M. Taylorandautocraft-bot[bot] b7174dc92d Engine: bounded DTD validation, compound-path hole orientation
* dtd: bounded matching steps, element depth and problem count

* address review: stop DTD matching when a step charge fails; refuse hole orientation past its budget

* Apply review fixes

- crates/engine/src/dtd.rs

---------

Co-authored-by: autocraft-bot[bot] <354215646+autocraft-bot[bot]@users.noreply.github.com>
2026-11-12 06:27:59 -05:00
Dylan M. Taylor 26d5c8941c IDML: story export and object-style overlay in linear time, embedded image budget
* idml: story runs and marker offsets found once, object-style overlay by position, embedded image budget

* address review: saturating embedded-bytes counter

* address review: IDML export past the embed limit succeeds and warns for each image written as a link

* address review: an unlinked image is always embedded, only linked ones fall back to their link
2026-11-12 06:27:41 -05:00
Dylan M. Taylor a41fc046f3 Data merge: a record range stops expanding once the limit is met
* Data merge: a record range stops expanding once the limit or the record count is met
2026-11-12 06:27:35 -05:00
dotCooCoo ed9980fec2 Paste: params text gives the pasted image's size as one point per pixel
edit.pasteImage sizes a new frame as File › Place does, which reads a
raster at one point per pixel and does not read a stored resolution.
The params text and the comment said otherwise.
2026-11-12 00:39:11 -08:00
dotCooCoo b1a514fc51 Paste: ui.paste checks the image's size before decoding it
ui.paste {image} refuses base64 longer than the 256 MB file limit
before it decodes the data, with the same check edit.pasteImage uses.
2026-11-11 22:05:16 -08:00
dotCooCoo 4122adc65f Text wrap: Alpha Channel outlines in use are looked up in sets 2026-11-11 22:04:10 -08:00
dotCooCoo ad828bd650 Text wrap: an opaque image's Alpha Channel contour is its rectangle
Before, an image with no transparency wrapped like its frame, so a smaller image or one moved within its frame kept text out of the frame's empty part.
2026-11-11 22:00:14 -08:00
dotCooCoo 8463cef4a9 Paste: refuse damaged clipboard images and journal one entry per paste
- edit.pasteImage decodes the whole raster before it stores the image,
  so a file whose pixels are cut off after a whole header is refused.
- edit.pasteImage is the only journal entry for a paste; the file.place
  it runs no longer adds a second one, so a replay places the image once.
- Empty clipboard text beside an image counts as no text, so Edit >
  Paste pastes the image.
- With a native menu, a pasted image event is ignored while the
  clipboard still holds what it held when objects were copied here.
2026-11-11 21:59:10 -08:00
dotCooCoo 544ebaf571 Text wrap: a relinked image's new outline recomposes the text around it
- each traced Alpha Channel outline has a serial number, and the composition signatures include the outlines in use, so a relink or link update that changes only the image data no longer leaves text laid out around the old image
- a wrap with the default alpha threshold is saved without it, as before thresholds were stored
- docs/typography-parity.md says Alpha Channel contours follow the image's visible pixels
2026-11-11 21:33:53 -08:00
.CooCoo 6fff5328eb Tests: type.align refusal cases name the check that refuses each (#2662)
Follows #2645. Its test said a misspelled key used to apply Align Left.
Only empty params and a bare string did; the parameter check already
refused a misspelled key, and the value parser refused an unknown
value. Each case now asserts the refusal message it gets.
2026-11-12 04:52:41 +00:00
dotCooCoo 630b5dfc43 Paste: images on the system clipboard paste as embedded images (#2204)
Paste ignored a bitmap on the system clipboard: a screenshot or an image
copied in a browser had to be saved and placed. Paste now places it.

- edit.pasteImage {base64, name?, spread?, at?} embeds the image in the
  selected empty frame, or in a new frame centered on `at` at its stored
  resolution (72 ppi when none) and at most 60% of the page width, as
  File > Place sizes it. Save and reopen and IDML export keep the pixels.
  Images over 64 million pixels and names without an image extension are
  refused.
- Ctrl/Cmd+V pastes the image egui delivers with no text, and Edit >
  Paste reads the clipboard's bitmap, or the first image file of a copied
  file list, when there is no text or the text is only an address.
- The menu read waits at most 1.5 s on its own thread, with one read in
  flight at a time.
- With a native menu, objects copied here still paste as objects until
  the pasteboard's change count shows a newer copy.
- ui.paste takes {image} for the control channel.
2026-11-11 20:50:24 -08:00
dotCooCoo 9cea62b238 Type: a repeated alignment records no undo step; menu-bar inserts stop with the window's shortcuts
- Align Left, Center, Right, Justify Left, Justify All Lines and
  type.align leave the document and the undo list alone when every
  target paragraph already has that alignment as its own value.
- On the Mac, Em Space, En Space and Current Page Number from the menu
  bar also do nothing while Quick Apply or a dialog is open, an input
  method is composing or a canvas context menu is open, the cases that
  stop the window's own shortcuts.
- Tests for both, and for Justify All Lines across threaded frames,
  over a paragraph style, through IDML export and import, and with
  parameters it does not take.
2026-11-11 20:48:43 -08:00
dotCooCoo b73c21db37 Data merge: a file that is not an image does not hide a later image candidate
The image search stopped at the first file that could be read and
checked whether it decodes afterwards. A non-image file at an earlier
candidate (the drive root, or beside the data file) then hid a valid
image beside the data file or the document, and the field was reported
missing. The decode check now runs inside the search, so only an image
ends it.
2026-11-11 20:36:39 -08:00
dotCooCoo f27e2c380b Data merge: overset count composes with the merged images' Alpha Channel outlines 2026-11-11 20:30:25 -08:00
dotCooCoo 97ed25093f Text wrap: a vertical open path keeps its offset, and previewed images are traced
A contour's zero-width spans (a vertical open path) are kept until the
wrap offset widens them, so text no longer crosses such a path. A record
previewed into an image placeholder gets the image's Alpha Channel
outline, as an edit would.
2026-11-11 20:23:59 -08:00
dotCooCoo fc09aa9124 Merge main into feat/type-shortcuts 2026-11-11 20:23:58 -08:00
dotCooCoo 9fcab8e66b Text wrap: Alpha Channel outlines fit composition, and an empty one wraps nothing
An outline with more path elements than composition follows is traced on
a coarser grid, so a fragmented image keeps an Alpha Channel contour
instead of falling back to the frame. An image with no pixel more opaque
than the threshold leaves the text alone.
2026-11-11 20:13:21 -08:00
dotCooCoo 5b89a13c2e Text wrap: anchored images keep their Alpha Channel outline
Outlines are traced for images anchored in text as well as for those on
the spreads, so an anchored image's Alpha Channel contour follows its
visible pixels instead of falling back to the frame.

Tracing reads the pixels once: a coarser grid, used when the outline has
too many edges, is made from the finer grid's mask when each side halves,
and the cell of each pixel is counted along the row instead of divided.
2026-11-11 20:04:50 -08:00
dotCooCoo 1fbb7e86b0 Merge #1084 (Alpha Channel text wrap) into main 2026-11-11 19:50:30 -08:00
dotCooCoo 099b89f53d Preflight: check the document on a background worker, not on every edit
The status bar's error count ran the whole-document preflight check on
the interface thread for every new state of the document, so every drag
step and every typed character waited for it. The Preflight panel ran
the same check on every frame. The check composes every story and asks
the file system about every linked graphic, so its cost grows with the
document: on a 300-page document with 900 placed images it took 137 ms
on a fast machine, and moving or resizing a frame and typing became
unusable on large documents.

The check now runs on a worker thread that takes the newest state of
the document; the issues last found stay shown until it answers. An
unchanged document is checked again every few seconds for linked files
changed outside the app, a save under a new path or a font reload is
checked again, and a check blocked on another document's linked file
is handed off to a fresh worker after 200 ms. Tests and the web build
check on the interface thread, once per state of the document.

preflight::check_document takes the document, the composition cache and
the save path, so the worker needs no session.
2026-11-11 18:53:44 -08:00
dotCooCoo 7809f5e9da Text: frame columns, gutter, switches and indents are checked too
object.textFrameOptions refuses a gutter outside 0 to 15552 pt, a column
count outside 1 to 40 (it was clamped) and an on/off option that is not
true or false (it was skipped). The Control bar's Columns field stops at
40, as the other column fields do. The params text gives the ranges and
lists flexibleWidth.

type.para and paragraph style create and edit refuse left and right
indents outside 0 to 15552 pt and first and last line indents outside
-15552 to 15552 pt. A style made from the selection is checked with the
values it takes from the selection.

style.paragraph.apply and style.paragraph.redefine check that Minimum,
Desired and Maximum stay in order in each justification row they change,
over the overrides paragraphs keep, and refuse the change otherwise.
2026-11-11 18:42:32 -08:00
dotCooCoo d490e0fb18 Data merge: a QR field at a text insertion point is refused instead of written as text
Insert Field with a QR column and the text cursor in a frame added a text placeholder, so a merge wrote the QR payload as plain text. It now returns "qr placeholders bind to a frame" and leaves the story unchanged.
2026-11-11 18:14:15 -08:00
dotCooCoo e90517be45 Text: paragraph spacing and justification values are checked
type.para, style.paragraph.create and style.paragraph.edit accepted any
number for paragraph spacing and justification. They now refuse Space
Before, Space After and same-style spacing outside 0 to 15552 pt, word
spacing outside 0% to 1000%, letter spacing outside -100% to 500%, glyph
scaling outside 50% to 200%, Auto Leading outside 0% to 500%, and a
Single Word Justification other than left, center, right or
fullyJustified. Each justification row needs Minimum <= Desired <=
Maximum over the values the paragraph or style resolves to after the
change, including the styles based on an edited style and the
paragraphs, table cells and notes that use them.

object.textFrameOptions refuses an inset outside 0 to 15552 pt or a list
that is not four sides, and a verticalJustification, firstBaseline,
autoSize or columnsKind that is not one of its names. These were applied
or skipped without an error before. IDML import reads these values as
before.
2026-11-11 17:51:19 -08:00
dotCooCoo e362820bc4 Data merge: an image field in text places the image, not its path
An image field inserted at a text insertion point, or typed there as
<<name>>, merged as text, so each record showed the image's path.
It now merges as an inline image at its natural size, scaled down to
fit the smallest text column of the story's frames. A missing file is
listed in missingImages and its marker is removed. An explicit image
role at a text insertion point places an inline image too.

An image path that starts with one separator (\Photos\a.jpg) is tried
from the drive's root first, then beside the data file and the
document.
2026-11-11 17:42:24 -08:00
.CooCoo b284052acc Type: type.align without a value is an error (#2645)
type.align with no `align` key applied Align Left, so a call that
misspelled the key, or passed a bare string, changed the paragraphs to
left alignment instead of failing. The command now returns an error,
leaves the text unchanged and records no undo step. A named value still
applies, and `align: null` still removes the override.
2026-11-12 01:30:21 +00:00
dotCooCoo 9f4bc29c3e Tables: a malformed table id is refused with nothing in a table selected
With nothing in a table selected, a table command given a `table` that is not a nonnegative integer (`null`, a string, a negative number) was refused as disabled, since the enablement check read it as no table. It is now refused with "`table` must be a nonnegative integer", as it is with a table selected.
2026-11-11 13:31:04 -08:00