Commit Graph
11048 Commits
Author SHA1 Message Date
BFlat 6dd99ef1e2 Merge pull request #6741 from dotCooCoo/fix/edit-colors-param-types
Edit Colors: a switch or number of the wrong type is an error instead of the default
2026-11-12 09:09:17 +07:00
BFlat d1a9c5a49c Merge pull request #6728 from dotCooCoo/feat/conic-gradient
Gradients: conic gradients sweep the stops once around the center
2026-11-12 09:09:08 +07:00
BFlat ebc18ffce7 Merge pull request #6742 from dotCooCoo/fix/long-path-frame
Render: a long path is checked against the rasterizer's limits from its kept boxes
2026-11-12 09:08:25 +07:00
BFlat 8f65aaa7fb Merge pull request #6718 from dotCooCoo/fix/issue-6634
Fix #6634: Pen closing drag no longer gives the first anchor symmetric handles
2026-11-12 09:08:12 +07:00
BFlat b8ebfdca09 Merge pull request #6730 from dotCooCoo/fix/ai-mesh-ink-tint-order
.ai/EPS import: gradient mesh corners in several inks take their tints last ink first
2026-11-12 09:07:59 +07:00
BFlat 358a47c559 Merge pull request #6737 from dotCooCoo/feat/control-bar-options-menu
Control bar: the panel menu turns each group of options on or off
2026-11-12 09:07:47 +07:00
BFlat 0cab083612 Merge pull request #6743 from dotCooCoo/feat/paste-on-selected-artboards
Edit: Paste in Place, in Front and in Back put a copy on each selected artboard
2026-11-12 09:07:36 +07:00
BFlat 5f2592e4fa Merge pull request #6732 from dotCooCoo/fix/plugin-removed-rename-back
Plug-ins: a failed rename back of a removed plug-in's settings is reported and undone later
2026-11-12 09:07:24 +07:00
BFlat 30b8a1e8b5 Merge pull request #6733 from dotCooCoo/feat/symbols-sort-and-list-views
Symbols: the panel menu sorts by name and offers Small and Large List views
2026-11-12 09:07:13 +07:00
BFlat b9d056986d Merge pull request #6734 from dotCooCoo/feat/para-style-options-sections
Paragraph Styles: Style Options edits indents, spacing, composition, hyphenation and justification
2026-11-12 09:07:00 +07:00
BFlat 8869c137eb Merge pull request #6735 from dotCooCoo/fix/graph-param-types
Graphs: graph.setType, setData and create refuse params of the wrong type
2026-11-12 09:06:48 +07:00
dotCooCoo 7de42c294d Render: a long path is checked against the rasterizer's limits from its kept boxes
Before drawing a shape, the renderer checks that its control points stay
within the rasterizer's limits. For a long path it measured every point
of the path for this check in each frame. The kept path of a long path
now keeps the box of the points of each run of segments next to the run's
bounds, updates it with the runs an edit changes, and answers the check
from those boxes.

With a closed path of 200,000 anchors and no paint (release build,
single-threaded, medians of 21 frames), the part of the frame redrawn
after one anchor moves took 1.93 ms instead of 2.69 ms, and drawing the
same part again with nothing changed took 0.015 ms instead of 0.343 ms.
2026-11-11 17:11:14 -08:00
dotCooCoo 5187e4b8a1 Edit Colors: a switch or number of the wrong type is an error
The Edit Colors commands read `fill`, `stroke`, `includeImages` and
`includePatterns` with a reader that fell back to the default for any
value that is not true or false, so `edit.colors.toGrayscale
{"fill": "false"}` converted the fills it was asked to leave alone.
These keys, and `convert` and `mode` in `edit.colors.adjustBalance`,
are now read with `switch_or` and `text_param`, and a wrong type is an
error that changes nothing. The same applies to `addon.color.filter`,
which shares the scope.

`edit.colors.overprintBlack` now refuses a `remove`, `fill`, `stroke`,
`includeCmyBlacks` or `includeSpotBlacks` that is not true or false
and a `percentage` that is not a number. `color.harmony` refuses a
`rule` or `variation` that is not a string; a `variation` such as 5
was dropped before.

A null still counts as a key left out. docs/mcp.md describes the
errors.
2026-11-11 17:08:11 -08:00
dotCooCoo 9998f020ac Edit: Paste in Place, in Front and in Back put a copy on each selected artboard
With the Artboard tool selecting several artboards, Paste in Place, Paste
in Front and Paste in Back put a copy of the copied art on each, where it
was on the artboard it was copied from, in one undo step. The three
commands take `artboards: [index...]`; the app passes the Artboard tool's
selection there, and without it the engine uses that selection while the
tool is chosen and records it in the journal. Art copied from no artboard
keeps its place on the first artboard and its offset to it on the others.
Copied artboards still paste once, where they were.

An `artboard` or `artboards` value that is not an artboard index of the
document, a repeated index or an empty list is now an error, and nothing
is pasted. An out-of-range `artboard` used to paste the art where it was.
A batch keeps the `artboards` a paste step names, and a paste step that
names neither pastes on the Artboard tool's selection while that tool is
chosen with several artboards selected.

Help page: https://helpx.adobe.com/illustrator/desktop/create-manage-artboards/organize-manage-artboards/cut-copy-and-paste-artboards.html
2026-11-11 17:00:44 -08:00
dotCooCoo 23d371ca28 Graphs: graph.setType, setData and create refuse params of the wrong type
graph.setType read `axisMin: "10"` as a cleared bound, so the axis went
back to the calculated range, and it ignored a string or number given for
a true/false option, a string for a number and a number for a text option.
graph.setData and graph.create ignored a `csv` that is not a string and
`series`, `categories` or `rows` that are not lists, and read a string in
`rows` as a blank cell.

The three commands now refuse such a value with an error naming the key,
and leave the graph and the undo history as they were. A null is still
read as a key left out, and a null axis bound still goes back to the
calculated value. A negative tick count is refused too.
2026-11-11 16:41:13 -08:00
dotCooCoo 6b4056a447 Control bar: the panel menu turns each group of options on or off
The Control bar's panel menu lists the bar's groups of options above
Dock to Top and Dock to Bottom, each checked while it is on. A click
turns that group off or on, and a group that is off stays out of the
bar even while its tool or object is selected. A group that is off
takes no room, so the groups after it fit a narrower window. The menu
scrolls in a window too short for all its items.

- window.control.options {group, visible?} sets or toggles a group and
  returns {group, visible}; an unknown group or a non-boolean visible
  is an error and changes nothing.
- The groups are off only by choice: every group starts on. The choice
  is kept with the preferences and with each workspace; files saved
  without it show every group, and unknown ids are dropped on read.
- The Artboard tool's bar follows the Artboard Options and Transform
  groups; with Image Options off, an image shows neither its controls
  nor Fill and Stroke.
- New labels have rows in every complete catalog.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-11 16:40:10 -08:00
dotCooCoo 45e6aa4948 Tests: MCP Pen closing drag keeps a clicked first anchor a corner
tests::pen::a_drag_from_the_first_anchor_closes_the_path expected the
closing drag to give the first anchor an outgoing handle mirroring the
incoming one, which is the behavior #6634 reports. The first anchor is
placed by a click, so after the close it stays a corner with its
outgoing handle at the anchor. The test now checks that.
2026-11-11 16:39:55 -08:00
dotCooCoo e4a126f08d Paragraph Styles: Style Options edits indents, spacing, composition, hyphenation and justification
Double-clicking a paragraph style, or Paragraph Style Options... in the
Paragraph Styles panel menu, opens Paragraph Style Options
(`ui.paraStyleOptions`) instead of the rename dialog. Its sections are
General (name and stored attributes), Basic Paragraph Formats (Alignment,
indents, space before and after), Composition (composer, Roman Hanging
Punctuation), Hyphenation and Justification. OK runs the new
`paraStyle.edit {name, to, attrs}`, which replaces the name and attributes
in one undo step; paragraphs that use the style keep their local
overrides. Fields left as they were keep the style's values, empty fields
leave an attribute unset, Preview can be canceled, and each section's
Reset Panel (`ui.paraStyleOptions.resetPanel`) clears only its own
attributes. New Paragraph Style shows the same sections, filled in from
the selected paragraph or the interface language's paragraph defaults.

`paraStyle.new`, `paraStyle.setAttrs` and `paraStyle.edit` now reject a
changed indent or space outside -1296 to 1296 pt, Hyphenation counts and
zone outside their ranges, Justification values outside their ranges or
out of Minimum/Desired/Maximum order, and tab positions outside 0 to
100000 pt. A value the style already holds is kept.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-11 16:34:42 -08:00
dotCooCoo c0be73df11 Symbols: the panel menu sorts by name and offers Small and Large List views
The Symbols panel menu gains Sort by Name, which puts the document's
symbols in name order, ignoring case, as one undo step
(`symbol.sortByName`). Symbols whose names differ only in case keep their
order, the current symbol stays current, and no undo step is added when
the symbols are already in order.

The menu's Thumbnail View and List View become Thumbnail View, Small List
View (18-point rows, 14-point thumbnails) and Large List View (the former
List View's 26-point rows and 22-point thumbnails), as in the Graphic
Styles panel. Clicking, double-clicking and dragging a symbol work the
same in every view.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-11 16:29:20 -08:00
dotCooCoo d262c65b14 .ai/EPS import: gradient mesh corners in several inks take their tints last ink first
Under an `/NChannel` color space a mesh corner gives one tint for each
ink. The reader now pairs the tints with the inks in the opposite order
to the listing, for process and spot inks alike: under
`[[Yellow] [Magenta] [Cyan] 3 /NChannel]`, `0 0 1` is full yellow. No
public document describes these records. This is VectorCraft's reading
of them, and under it the meshes match the flattened page that the same
file carries.

The reader gave the first tint to the first ink listed, so mesh areas
came in with the wrong inks, yellow as cyan. Where enough of the art
changed, the layers no longer matched the file's page, and the file
opened as its page instead of its objects.
2026-11-11 16:24:48 -08:00
dotCooCoo 74f523ae8b Merge main into fix/plugin-removed-rename-back 2026-11-11 15:52:10 -08:00
dotCooCooandGert Pellin 1b744eae52 Gradients: conic gradients sweep the stops once around the center
A fourth gradient kind, conic (also accepted as `angle` or `conical`),
sweeps the stops once around the center (the gradient's start),
clockwise on the page from the vector, with a seam where the last stop
meets the first. A negative aspect mirrors the sweep, and reflecting an
object turns its sweep the other way, also for a conic without a
vector or with a flat extent.

- Gradient panel: a Conic button in the Type row; the Aspect Ratio
  field works for conic gradients and keeps a mirrored sweep mirrored.
- Gradient tool: the extent ellipse, aspect handle and center ring of a
  radial gradient, without a focal point.
- Rendering, swatch chips, transforms, warps, plug-in round trips, and
  Object > Expand into wedges or a mesh of columns around the center.
- Commands: a negative `aspect` is an error for linear and radial
  gradients, and so is a `focal` point for a conic gradient.
- PDF export writes a function-based shading whose calculator function
  turns the angle into the ramp, and PDF import reads a function-based
  shading that turns around the origin of its space back as a conic
  gradient, also when that origin lies outside the painted area. A
  PDF/A file, or a conic with more than 97 stops, gets an image
  instead.
- SVG export writes 360 solid wedges clipped to the shape for opaque
  stops and an image otherwise, and a linear gradient on characters.
- CSS export writes `conic-gradient(from ...)`, with the stops mirrored
  for a mirrored sweep.
- EPS and legacy .ai export write 360 solid wedges; the .ai editing data
  holds a linear gradient along the vector with the same stops.
- .af files: conical gradients open as conic gradients.
- An export that writes the gradient in another form gives a warning.

Supersedes #2326 and includes switch87's code from it.

Co-authored-by: Gert Pellin <gert@pellin.be>
2026-11-11 15:51:11 -08:00
dotCooCoo ef7fbaac31 Plug-ins: a failed rename back of a removed plug-in's settings is reported and undone later
When plugin.remove could not remove the grant and then could not rename
the plug-in's settings folder back from <folder>.removed, the failure was
only logged: the plug-in got empty settings, and the next removal deleted
the .removed folder with the settings in it.

- The error now names the .removed folder, the plug-in folder and the
  reason, and the plug-in gets no storage until the settings are back.
- The next load, install or plugin.remove of the plug-in renames a kept
  folder back while the plug-in has no folder of its own. When it has one,
  that folder is used and the kept one stays until plugin.remove deletes
  both. A removal while a kept .removed folder exists renames the plug-in
  folder to <folder>.removing.
- Before deleting a renamed folder, the store writes an empty
  <folder>.removed.delete file and removes it once the folder is gone, so
  what a failed deletion leaves is not moved back. When that file can't
  be written, nothing is deleted.
- A .removed folder without a .delete file, including one an earlier
  version left, counts as kept settings: a new install of the id needs
  replace: true, and plugin.remove of the id deletes it.
2026-11-11 15:51:11 -08:00
dotCooCoo e6add18663 Fix #6634: Pen closing drag no longer gives the first anchor symmetric handles
Closing a path by dragging on its first anchor made that anchor smooth
with symmetric handles, so the first segment bent along with the closing
one. The drag now sets the first anchor's incoming handle to the mirror
of the pointer. Its outgoing handle stays where it is on a corner, so
the first segment keeps its shape, and on a smooth anchor it turns to
stay in line at its own length. Alt makes the anchor a corner and leaves
the outgoing handle where it was when Alt went down. A click on the
first anchor closes the path with the incoming handle retracted and the
anchor a corner, so the closing segment comes in straight.

The Smart Pen's closing drag follows the same rule.

path.close's `in` now places the handle as path.setHandle does, and a
new `out` param places the outgoing handle and makes the anchor a
corner.
2026-11-11 15:33:09 -08:00
FredApps 7f3a046b18 CI: nightly release dry run (#6678)
release.yml also runs nightly on main with craft-common-actions' dry-run: every release build
except macOS, with nothing signed, pushed or drafted. Breakage that only the release build hits
(riscv64, Flatpak, FreeBSD, packaging) then shows up the next morning instead of on release
day, as it did on 11 Nov 2026.
2026-11-11 23:04:49 +01:00
Dylan M. Taylor 566f720868 SVG import: references follow an id's first element, one read per linked file, bounded blank lines (#5409)
* fix(svg): first element of an id, shared linked file reads, bounded blank lines

* address review: cache failed linked-image reads but give each href its own placeholder and link

* address review: charge only blank lines to the line-break budget

* address review: a collapsed line break keeps its measured leading in tiny type

* address review: blank lines use the same scaled leading tolerance
2026-11-11 16:11:34 -05:00
Dylan M. Taylor 8e8b43f045 ci: use StepSecurity's maintained actions (#6658)
Each third-party action that StepSecurity publishes a secure drop-in
replacement for now uses that replacement, pinned to a commit with its
version as a comment. Versions follow what we used: the newest
StepSecurity release in the same major, or the closest major they
publish. dtolnay/rust-toolchain refs that named a toolchain (stable,
nightly, 1.76) become the replacement's `toolchain` input.
2026-11-11 16:02:52 -05:00
BFlat b08e421445 Merge pull request #6651 from dotCooCoo/fix/simplify-flat-loops-keep-area
Simplify: a closed subpath whose refits enclose no area keeps its outline
2026-11-12 03:20:46 +07:00
BFlat 6e873b806c Merge pull request #6657 from dotCooCoo/fix/js-random-seed-test
Scripts: test that the OS random value seeds Math.random
2026-11-12 03:16:14 +07:00
BFlat dd6b00c228 Merge pull request #6653 from dotCooCoo/fix/script-throw-site-through-finally
Scripts: an uncaught error that passes through a finally block is reported where it was thrown
2026-11-12 02:53:22 +07:00
BFlat f9ff1caf54 Merge pull request #6648 from dotCooCoo/feat/dynamic-text-on-path
Type: Dynamic Text sizes type on a path to fill its brackets
2026-11-12 02:45:39 +07:00
BFlat e0779c6266 Merge pull request #6646 from dotCooCoo/fix/plugin-fuzz-fuel-slice
Plug-ins: the fuzz test reads the runtime's fuel slice instead of a copy
2026-11-12 02:28:28 +07:00
dotCooCoo 27c24a4f53 Scripts: test that the OS random value seeds Math.random
random_seed passes the OS random source's result to random_seed_from, so a test can
give it a known value and check the seed it makes, instead of only reading the source text.
2026-11-11 11:25:25 -08:00
BFlat 1c049233af Merge pull request #6645 from dotCooCoo/fix/js-random-seed-web
Scripts: Math.random gets a new seed on every web page load
2026-11-12 02:24:16 +07:00
BFlat 541f8beae7 Merge pull request #6643 from dotCooCoo/feat/pdf-large-pages-in-points
PDF: an option writes pages longer than 200 in at full size in points
2026-11-12 02:05:54 +07:00
BFlat c70d320d64 Merge pull request #6639 from dotCooCoo/fix/issue-6622
Part of #6622: Help Bar hints and tool names show in full on hover when clipped
2026-11-12 02:01:07 +07:00
dotCooCoo 796e2a7ebc Simplify: a closed subpath whose refits enclose no area keeps its outline
Follows #6614. When a closed subpath's refit in two and in three parts is
still lines that enclose no area, for example an S curve closed by a
straight edge whose cut points all lie on that edge, Simplify now splits
each segment in 2, 4, 8 and so on (up to 1,024 pieces, 65,536 in all)
until every piece is within the tolerance of the line between its ends
and those lines enclose an area. With Convert to Straight Lines those
lines are the result; without it the subpath stays as it is. A subpath
whose points are all in line keeps the refit's lines, so its extra
anchors are still removed. Lines count as enclosing no area when every
point is within 1e-6 pt of one line.
2026-11-11 11:00:51 -08:00
BFlat c6580dbda0 Merge pull request #6636 from dotCooCoo/fix/plugin-folder-tests-take-turns
Tests: plug-in folder tests take turns on the folder last loaded
2026-11-12 01:56:39 +07:00
BFlat 3dda59ce95 Merge pull request #6640 from dotCooCoo/fix/ids-null-takes-selection
Commands: ids null acts on the selection instead of being refused
2026-11-12 01:56:30 +07:00
BFlat d0bb662aa2 Merge pull request #6641 from dotCooCoo/fix/scriptcheck-identifier-chars
Script checker: names follow Unicode ID_Start and ID_Continue
2026-11-12 01:52:02 +07:00
dotCooCoo 1f835d94c4 Merge main into fix/script-throw-site-through-finally 2026-11-11 10:44:55 -08:00
dotCooCoo 8d094fc811 Scripts: an uncaught error that passes through a finally block is reported where it was thrown
An error a finally block passed on unchanged was reported at the end of
that block, in script.run's report and in the Script Console, because the
block's end raised the error again at a new site. The interpreter now keeps
the site of the exception each finally block runs for, keyed by the stack
slot that holds it, and the block's end throws the exception on from that
site. This holds through nested finally blocks, called functions, resumed
runs and marked host errors. An error the finally block throws is reported
at that throw, and one its return, break or continue discards is not
reported.
2026-11-11 10:44:16 -08:00
BFlat 6a4ef12091 Merge pull request #6603 from Messhias/feat/g5-brush-lib-energy-beams
G5: built-in Energy Beams brush library
2026-11-12 01:43:54 +07:00
dotCooCoo 2606b70604 Type: Dynamic Text sizes type on a path to fill its brackets
Type › Dynamic Text (`type.dynamicText`, also on the Contextual Task Bar
for type on a path) scales the text by one factor so it fills the span
between its start and end brackets, and the layout fits it again after
each edit to the text, the path or a bracket. The first character's
size moves in 0.1 pt steps within 0.1 to 1,296 pt. Turning it off, or
threading the type, keeps the sizes it was drawn at.

- The model saves `dynamicText` only when on.
- SVG, the legacy .ai writer and the .ai editing data write the drawn
  sizes through `vectorcraft_text::drawn`; the editing data warns that
  the setting is not written.
- Shrink Text to Fit and Dynamic Text step the size the Character panel
  shows when a size measures the cap height, x-height or ICF box.

Docs: docs/mcp.md, docs/type-parity.md, docs/target-app-parity.md.
Part of #4134.
2026-11-11 10:42:49 -08:00
BFlat 9840b65a85 Merge pull request #6626 from dotCooCoo/fix/js-xml-copy-and-insert-fuel
JavaScript: new XML copies a one-item list's node, and insertChildAfter and insertChildBefore take fuel per child scanned
2026-11-12 01:35:54 +07:00
BFlat 1e76791ae1 Merge pull request #6615 from dotCooCoo/feat/script-file-folder
Scripts: File and Folder read files in the script's own folder
2026-11-12 01:35:45 +07:00
dotCooCoo 3fba3a440c Merge main into fix/plugin-fuzz-fuel-slice 2026-11-11 10:32:47 -08:00
BFlat f83d916d8a Merge pull request #6631 from Hassan1305/docs-6340-rotation-direction
Commands: every angle and rotation param says which way it turns (#6340)
2026-11-12 01:32:17 +07:00
BFlat 210e9ad7d0 Merge pull request #6632 from dotCooCoo/feat/ruler-guides-as-objects
Guides: ruler guides are document objects on their layers
2026-11-12 01:32:07 +07:00
dotCooCoo 6fbaad6c5e Scripts: Math.random gets a new seed on every web page load
Each realm seeded Math.random from std's RandomState. On
wasm32-unknown-unknown its keys come from stack and heap addresses,
which are the same on every page load, so scripts in the web build
drew the same sequence each time the page opened.

The seed now comes from getrandom (crypto.getRandomValues in the
browser, as crates/pdf/src/encrypt.rs already does), with RandomState
kept as the fallback when it fails.
2026-11-11 10:31:32 -08:00