Commit Graph
1443 Commits
Author SHA1 Message Date
dotCooCoo 8ce6177c62 Arrange: a layer id given to Send to Back and the other selection commands is refused
Squashed from #3951 onto main.
2026-10-24 18:16:24 +07:00
Taha-Mahmoodi 97f84723ef Fix #3965: an unresolved step reference given as id is refused under the command's name; effect.apply keeps its effect-naming id 2026-10-24 17:57:21 +07:00
Taha-Mahmoodi c40113b755 Fix #3965: a malformed or unknown id is refused under the command's name, never replaced by the selection 2026-10-24 17:57:20 +07:00
Taha-Mahmoodi 8c5714a260 Fix #3965: id works as ids of one with nothing selected wherever params take ids?|id? 2026-10-24 17:57:18 +07:00
Fabian GrajalesandClaude Opus 5.5 1adbf259f7 Open .ai files with their swatches: the palette, its colour groups and unused spot colours
The editing data's palette (%AI5_BeginPalette) was skipped, so a .ai file
opened with the default swatches plus only the spot colours its art used:
inks the art doesn't use (a Pantone set kept in the file) and colour groups
were lost. The palette is now read in order (process, spot in CMYK, RGB or
Lab, and global colours, gradients and patterns, colour groups; versioned
content read once) and replaces the default swatches.

Xs/Xz (Registration at a tint, as printer's marks use it) are read as the
Registration swatch: before, art painted with them stopped the editing data
from being read at all.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 17:46:20 +07:00
vectezaandClaude Opus 5.5 1a6bc267d5 Dimension tool: Linear picks show and snap to Smart Guides
Picking the two points of a Linear dimension snapped to anchors and to the
line under the pointer, but showed no guides and ignored the art around it.
The picks now go through the drawing tools' Smart Guides (DrawSnap), hovering
too, so the guides show before each click: a point slides into line with other
objects' anchors and centres, and the second onto the construction guides
through the first. An anchor of the line under the pointer still wins (it
links the dimension to that path), then a guide, then the closest point of the
line (#2432). The guides go once the dimension is being placed.

Test: linear_picks_show_and_snap_to_smart_guides (fails on the old tool, which
showed no overlays while hovering). docs/dimensions.md updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 17:46:19 +07:00
bflatastic 381b788f56 Slices: Lock Slices and Hide Slices deselect the slices and keep them deselected
Squashed from #2841 onto main.
2026-10-24 17:46:19 +07:00
dotCooCoo a7ef6ce78c Recolor: art linked to a group swatch keeps its color model
With model "keep" (the default), a row whose new color is in another
color model gives linked art the color converted into the art's model.
That art no longer stays linked to the rewritten group swatch, which
holds the color in its own model, and the reply's note reports the
conversion.
2026-10-24 17:46:15 +07:00
dotCooCoo b8436385e8 Recolor: art a row leaves unchanged loses its link to a rewritten group swatch
When recolor.apply with a group rewrites a global swatch with another
color than the row of the art linked to it, and that row leaves the art's
color as it is, the art now keeps the row's color and is no longer linked
to the swatch. Before, the link stayed and the group's rewrite gave the
art the swatch's new color.
2026-10-24 17:46:15 +07:00
dotCooCoo 5100a52a12 Recolor: recolor.apply with a color group keeps art linked to the group's global swatches
Art linked to a global swatch of the group that recolor.apply rewrites stays
linked when the swatch takes its row's new color: it shows that color at its
tint, and a later swatch.edit still reaches it. Before, the art took the new
color unlinked. With group, the reply adds relinked, the count of other linked
paints that followed the group's new colors.
2026-10-24 17:46:15 +07:00
dotCooCoo 640ddbd4c0 EPS: Use Artboards also writes a central file with every artboard
With Use Artboards and two or more artboards, EPS export now writes a
central file under the path's own name before the file of each artboard.
The central file contains the whole document, and its bounding box is
the visible art, as in an export without Use Artboards. An export of a
single chosen artboard still writes one file at the path's name, and
Export for Screens still writes one EPS per artboard. When no art shows,
only the artboard files are written.

Docs: the useArtboards params text, the MCP export tool's range text,
docs/mcp.md, docs/control-protocol.md and docs/target-app-parity.md.
2026-10-24 17:46:14 +07:00
dotCooCoo dbc1b69f1c Find Objects: document.find filters by bounds, size and anchor count and can select the matches
document.find took only name, kind and text, so removing hairline slivers or
every object in one region needed the whole inspect tree and a filter
written outside the app. It now also takes within and intersects
([x, y, width, height] in document points), min and max width, height,
thickness (the smaller side) and area of the geometric bounds, and min and
max anchor count (a compound path counts its members together). Each given
filter must match, and limits are inclusive.

select: true also selects the matches, leaving out hidden and locked
objects, matches inside another match, and compound path members unless
the compound path is isolated; the reply adds selected. Select > Reselect
repeats the find, and an action being recorded records a find that
selects. The count that select.color, the Select > Same commands and the
Select > Object commands report is now the number of objects selected,
after Lock Guides leaves out guide paths.
2026-10-24 17:46:13 +07:00
dotCooCoo c5d010e7d7 MCP: document.inspect and document.open report the File Info title as fileInfoTitle
The title field of document.inspect and the document.open reply is the
document's tab name, which comes from the file name once the document
is saved to or opened from a file. A client had to call file.info or
document.info to read the File Info title, so reading a saved
document's title from these replies gave the file name instead.

Both replies now add fileInfoTitle, the title file.info reports, and
keep title as it was. docs/mcp.md's File Info section describes both.
2026-10-24 17:29:33 +07:00
dotCooCoo 5f16fc3639 Image Trace: imageTrace.make refuses unknown keys inside params
imageTrace.make and imageTrace.makeAndExpand checked their own keys, but
not the keys inside `params`. A misspelled setting such as `colours` was
dropped, and the trace ran with the preset's value and no error.

A key inside `params` that is not a trace setting is now an error that
names the nearest setting, as for a command's own keys. Errors from
imageTrace.makeAndExpand, including those for `enhanced` and a missing
swatch library, name that command instead of imageTrace.make.
2026-10-24 17:29:33 +07:00
dotCooCoo 7da8edab79 Recolor: recolor.colors and recolor.reduce read the art Select All takes when nothing is selected
recolor.colors and recolor.reduce were unavailable with nothing selected, so
listing a document's colors needed a select.all first, which also changed the
selection. Both now take ids and read the selection when ids is left out.
With nothing selected they read the objects Select All takes and the objects
inside them: hidden and locked objects are left out with what they hold, also
inside a group, as are the objects of hidden, locked and template layers, and
in isolation mode only the isolated art is read. The selection is left
unchanged. An object named in ids or selected is read with everything it
holds, and an object listed twice, or listed together with a group that holds
it, counts once. recolor.apply still recolors only the selection.
2026-10-24 17:29:32 +07:00
dotCooCoo 500c84e2c7 Select: Same command descriptions state the compound-path rule
The params descriptions of Same Fill Color, Stroke Color, Fill & Stroke,
Graphic Style and Appearance Attribute say that a member path of a
compound path selected first compares as its compound path, except in
isolation mode inside that compound path.
2026-10-24 17:29:32 +07:00
dotCooCoo a272d49ea7 Select: Same commands for paint, appearance and shape select compound paths
Select > Same > Fill Color, Stroke Color, Stroke Weight, Fill & Stroke,
Opacity, Blending Mode, Appearance and Shape skipped containers, so they
never selected a compound path, even when the compound path was the
object selected first. With a member path of a compound path selected
first, these commands and Same Graphic Style and Appearance Attribute
compared the other objects with the member, which has no paint or style
of its own. Graphic Style then reported that the selection had no
graphic style, and Appearance Attribute that the object had no fill,
stroke or effect.

The eight commands now match a compound path on its own paint and
attributes, as select.color does, and skip its member paths. When a
member path is selected first, all ten commands compare the other
objects with its compound path. In isolation mode inside a compound
path, the member paths are matched as before.
2026-10-24 17:29:32 +07:00
Chris MainandClaude Opus 5.5 61504c84fb Print: turn only landscape paper, and only for macOS queues
Review of #3925: the spooled job turned every sheet wider than tall, so
custom paper that is wide in Portrait (a 4 × 2 in label) went to the queue
tall, and a Portrait + Transverse page was turned back. Only the sheets
whose paper the layout turned to landscape (not transverse) are written
upright now.

The desktop print service asked for upright pages on every platform, but
craft-print already turns each sheet to its own orientation on Windows:
only macOS asks for them now; Linux keeps main's behaviour.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-24 17:29:32 +07:00
Chris MainandClaude Opus 5.5 41430cc171 Print: landscape pages print upright on macOS print queues
A landscape print job was a page wider than tall, and `lp` on macOS puts
each page on the paper as it is: on upright Letter it printed unturned,
cut off on the right (checked with cupsfilter through an AirPrint
driver). Saving the PDF and printing it from Preview worked because
Preview turns the page.

`file.print` takes `forPrinter`: a page wider than tall is written
upright, the art turned a quarter anticlockwise as a printer driver turns
a landscape job. Page by page, so auto-rotated jobs that mix wide and tall
artboards print right too. The desktop print service asks for it
(`PrintService::turns_landscape`); saved PDFs, PostScript, the preview and
the browser's print dialog keep landscape pages as they are.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-24 17:29:32 +07:00
dotCooCoo 4c5c54ccbc Fix #3799: Alt held at the press draws a straight Pencil line at any angle
With Alt key toggles to Smooth Tool off, holding Alt when a Pencil drag
starts now draws one straight segment from the press point to the
pointer, at the angle the pointer takes, as Shift does at 45° steps.
Pressed on an end of a selected open path, the line continues the path
from that end. Both ends snap to Smart Guides as a stroke's ends do, and
the line stays open when Alt is still held at the release. Shift and Alt
together keep the 45° steps.

Before, a drag started and released with Alt held drew a closed freehand
path. Alt pressed after the drag has started still closes the path at
the release, and with Alt key toggles to Smooth Tool on, Alt still switches
to the Smooth tool. Before a Pencil press, Alt no longer shows the closing
cursor.

Docs: docs/target-app-parity.md, docs/ui-parity.md.
2026-10-24 17:29:32 +07:00
Taha-Mahmoodi 23c0e8c501 Fix #3964: Create Outlines stacks each run's ruby right after that run's glyphs, as the canvas paints it 2026-10-24 17:29:32 +07:00
Taha-Mahmoodi cab62cbb18 Fix #3964: Create Outlines, EPS, EMF/WMF and legacy .ai keep the ruby where the canvas draws it 2026-10-24 17:29:32 +07:00
bflatastic 7f8bc837bd Save options test: take the file name after either path separator (Windows) 2026-10-24 17:29:32 +07:00
dotCooCoo 11c61c97b1 Save: a remembered artboard pick follows the artboards it named
A save without options reuses the options the document was last saved
with in that format. Their artboard, artboards and range name artboards
by number, so once artboards were deleted or moved, the save wrote
other artboards or was refused: with three artboards, a PDF saved with
range "2" wrote the third artboard after the first was deleted, and one
saved with range "1, 3" was refused after the third was deleted. The
same held for SVG saves, a legacy .ai, and .ai and native files saved
with separateArtboards. file.formatOptions and SVG Options showed the
same numbers.

The document now keeps the ids of the artboards it had when it was
saved, and the remembered pick follows them: an artboard deleted since
is left out, one that moved is named by its new number, and the rest of
the pick is kept. A range open at its end ("2-") is written out as the
artboards it named once artboards are added. When none of the artboards
the save used is left, the pick is left out, and the save writes the
artboards it writes when none is named. A range of "all" stays as it
is. An artboard given to the save is still refused when the document
does not have it.

A new artboard no longer takes the id of an artboard deleted earlier in
the same document (Document::retire_artboard_id), or of one an undo took
away: the highest id given out is shared with the undo history, so a
new artboard is not taken for an earlier one.

file.revert keeps the pick only when the file read back has the
artboards the document had at the save, with the same ids in the same
order. A PDF saved with a range holds only those pages, and one saved
without preserveEditing reads back with new ids in page order, so their
picks are left out.
2026-10-24 17:20:48 +07:00
dotCooCoo 3e0f9795c2 Threaded text: Create Outlines and Expand on a frame no longer duplicate its text
Create Outlines on a frame of threaded text removed the frame, and the
thread's re-flow then added the frame's text to the story, as it does
for a frame that was deleted. The other frames held that text a second
time while the outlines drew it. Object › Expand, and Expand Appearance
where it outlines type or groups it with a shadow, outer glow or Crop
Marks, did the same.

An outlined frame now leaves its thread with the text it shows, and the
other frames keep the text they hold. When the thread's last frame is
outlined, the text it has no room for goes after the text of the last
frame that stays. When Expand Appearance keeps a frame as type in a
group, the type takes the frame's place in the thread. A thread left
with one frame is no longer a thread, and undo restores the thread.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-24 17:20:47 +07:00
Dylan M. TaylorandClaude Opus 5.5 20bba9ebae Security: linear work for shortcut review, gradients, recovery names, include cycles, batch references, DOCX style ids, CAD layouts and long strokes
CodeRabbit findings #2, #16, #31, #103, #114, #124, #162, #179, #182, #183, #185:

- Shortcut import review: example names for each code in one pass over the rows.
- Gradients: a midpoint stop is mixed from its two stops; freeform recolor samples its
  increasing positions with one advancing search (`Gradient::sample_increasing_with`).
- Recovery: image entry names are looked up by address, and dead ones swept when the map
  doubles, not on every image.
- Script checker: include cycles from strongly connected components (iterative Tarjan), not
  a reachability row per file.
- Batch step references copy at most 256 MB of values for one step.
- DOCX: style ids over 256 bytes are ignored where defined and where used.
- DXF: layouts keep at most 4 MB of names; a hatch's loops count against the node limit.
- Freehand and Liquify: past 1000 samples a drag previews every n/1000 samples, strokes keep
  at most 100,000 samples, and the stroke kept is previewed in full before it is committed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 17:19:59 +07:00
Dylan M. TaylorandClaude Opus 5.5 03d2f0e83c Security: file authority for stored paths, linked files, placed documents, font folders, recovery areas and atomic saves
CodeRabbit findings #7, #72, #92, #94, #95, #99, #100, #140, #158, #174:

- Link search hashes at most the size it looked at (a growing file no longer matches).
- Resolving links reads, decodes and previews each linked file once, shared by every key.
- Placed documents read inside one another resolve links at most 8 deep, never one already
  being read.
- A data set's image path and the placed-document rereader follow stored paths through
  `document_path` (no other computer's share).
- The Links panel looks at a linked file within the roots of the automation caller that
  opened the document.
- A fonts folder set by a confined caller is scanned without following links out of it.
- Recovery refuses an area folder that is a link or another account's.
- Atomic saves keep the replaced file's group and Linux access ACL, or make the replacement
  owner-only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 17:19:59 +07:00
Dylan M. TaylorandClaude Opus 5.5 b12ee928f3 Security: document model generation budgets for live art, clipping runs, placed documents, graph masks, path reading and native entries
CodeRabbit findings #58, #75, #82, #113, #159, #175, #187:

- Live evaluation (expansion, envelope mapping and everything inside) makes at most 4M
  objects (`MAX_GENERATED`); deep expansion counts what each live object makes, and envelope
  image pieces count before they are cut.
- Clipping runs copy at most 8M clip path elements together; past it runs are plain groups.
- Exports read at most 256 placed documents; the rest show their previews.
- Graph design and marker budgets count opacity-mask art (`Node::count_with_masks`).
- Native files read at most 32M anchors (4M on wasm) of paths; the web build allows 1 GiB of
  entries after the JSON.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 17:19:16 +07:00
aiongg 8cc69ed45c CI: one test binary per crate, nextest, line tables only (#3855)
* CI: line tables only for workspace crates, no debug info for dependencies

* CI: one integration-test binary per crate

Each crate's tests/*.rs files become modules of tests/it/main.rs. Files that change
process-wide state (Color Settings, the font database, installed plug-ins, the working
directory), the fuzz sweeps and the test targets the Affinity corpus workflow names stay
their own binaries.

* Docs: name the integration tests' new paths

* CI: xtask test with nextest and doctests, one wasm check, clippy --keep-going

cargo xtask ci runs the tests with cargo nextest (cargo test when it is not installed),
builds them with --lib --bins --tests, runs the doctests as their own step, and checks
the wasm crates in one cargo check --keep-going call.
2026-10-23 21:36:10 -04:00
Taha-Mahmoodi 767f06b20e Fix #3828: New Document › Branding offers Business Card 91 × 55 mm 2026-10-24 07:12:16 +07:00
el-j 71a669635c M2.1: prevent click-through on open path fills and support segment toggle (#3405) 2026-10-24 06:00:23 +07:00
Jürg Lehni caaccaf5be Type: images in SVG glyph documents draw with the glyph
They were left out because glyph art had no document to keep them in; since #3879 they hold their own pixels until a document takes them in.
2026-10-24 06:00:22 +07:00
bflatastic a564fe5d8e PDF export: pattern fills are written as tiling patterns (#3849) 2026-10-24 05:59:04 +07:00
bflatastic b2835c4f2b Tests: engine tests that add fonts to the shared font database take one lock 2026-10-24 05:52:15 +07:00
bflatastic 4eec70e5cd Automation roots: rustfmt and clippy (redundant closure) 2026-10-24 05:16:21 +07:00
Dylan M. Taylor e95e8418ed Audit: automation roots follow file.showPackage, the Place queue, headless file methods, clipboard files, placed-document workers and caches, folder searches and the recovery folder 2026-10-24 05:16:20 +07:00
Angelo BernardiniandClaude Opus 5.5 52a43eefdb G12: ruler guides nudged with art keep to the page's axes at a turned Constrain Angle
With objects and ruler guides selected together, object.nudge moved the
guides by the art's delta turned through General > Constrain Angle, so at
90 degrees a Right nudge moved a horizontal guide vertically. The guides
in that edit now move by the page-axis delta, as guides selected alone
already did (CodeRabbit finding on #3745).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014gCpjL3yUhaH3jRp7ksufh
2026-10-24 04:59:57 +07:00
BFlat e0c1548049 Merge pull request #3896 from storytold/fix/3869-svg-type-features
SVG export: type with small capitals, superscript, subscript or tab leaders is written as outlines (#3869)
2026-10-24 04:51:54 +07:00
aiongg 6877d6535f Links: resolve stored paths with craft-docpath's resolve_absolute (#3267)
* Links: use resolve_absolute for stored paths

* CI: release only with git dependencies from storytold

* Release: check git sources from the parsed Cargo.lock and cargo config

The grep let any character stand for the dot in github.com, passed a missing or stale
Cargo.lock, and missed source replacement in .cargo/config.
2026-10-23 17:51:28 -04:00
bflatastic 166afce360 SVG export: type with small capitals, superscript, subscript or tab leaders is written as outlines (#3869) 2026-10-24 04:49:08 +07:00
Dylan M. Taylor 9843d5f1ab Audit: export names, linked-file ids and MCP prompt arguments in one pass 2026-10-24 04:49:07 +07:00
bflatastic c2ad9f8bbb Type: emoji go with type that effects reshape and Expand Appearance
Squashed from #3879 onto main.
2026-10-24 04:49:06 +07:00
bflatastic 8e8aaa8683 SVG: a Preserve Editing SVG reopened from disk saves as the full document again (#3867) 2026-10-24 03:52:24 +07:00
Jürg Lehni e372d00cb7 Type: tests pin colour glyphs in variable fonts, on paths and on the canvas
A variable font's COLR layers follow its instance, a colour glyph turns with type on a path, and the canvas draws an SVG glyph's art in its own colours and the type's fill.
2026-10-24 03:52:23 +07:00
bflatastic 9f1a001a2b Export for Screens: a per-artboard EPS takes the artboard as its page, so an empty artboard still writes 2026-10-24 03:52:22 +07:00
bflatastic d81145aee3 Artboard documents keep objects without measurable bounds (type in a missing font) 2026-10-24 03:52:22 +07:00
bflatastic 60107cd33a Export for Screens: a document row for an artboard keeps only that artboard's art (#3868) 2026-10-24 03:52:22 +07:00
bflatastic 0066447eac Global Edit: cache the highlight outlines per document revision 2026-10-24 03:09:12 +07:00
bflatastic 6e3ecc3adf Select: Start Global Edit edits the objects of the same shape together, each in proportion
Squashed from #3781 onto main.
2026-10-24 03:09:12 +07:00
dotCooCoo 2a2e63856c Type: the Paragraph panel's Bullets button turns paragraphs into a bulleted list
VectorCraft had no lists. A bullet could only be typed as a character,
and the tab after it did not stop at the left indent. The reference app
turns paragraphs into a bulleted list from the Paragraph panel, the
context menu and Type › Bullets and Numbering › Apply Bullets.

text.setFormat takes list ("none" or "bullet") and bullet ("none",
"dot", "dash", "circle" or "square"). The layout draws the bullet before
the first line of each list paragraph that has text, in the font, size
and color of its first character, and starts the text at the next tab
stop, with the left indent counted as a stop. Wrapped lines start at
the left indent, and type on a path draws the bullet too. In a
horizontal right-to-left list paragraph the indents are mirrored: the
bullet hangs at the right, and the wrapped lines start at the right
where the first line's text starts after the bullet. The bullet is not
a character of the text. A paragraph whose left and first-line indents
are both 0 gets 18 pt and -18 pt when it joins a list. Return continues
the list, paragraph styles carry it, Reset Panel turns it off, and the
native file saves it only when it is set.

The Paragraph panel has a Bullets button with a list of the five
presets, and Type › Bullets and Numbering › Apply Bullets and the
context menu run type.applyBullets. Live SVG text writes the bullet's
character, and SVG writes type on a path with bullets as outlines. DXF
writes the bullet as a TEXT entity of its own, and legacy .ai export
warns that bulleted lists are left out. The caret, selections, Touch
Type and Show Hidden Characters skip the bullet.

Live SVG text of horizontally scaled type now writes each tab in a
tspan of its own. Before, the characters before a tab shared its tspan,
and its textLength made a viewer stretch them across the tab's gap.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-24 03:09:11 +07:00