Commit Graph
10704 Commits
Author SHA1 Message Date
dotCooCoo 394bbb37c0 Effects: placed gradients move and scale with the Warp effects
A gradient placed with the Gradient tool stayed where it was when the
object's Warp effect changed the outline, so the warped shape no longer
matched its gradient.

Under each Warp style the placed gradients of a path now move and scale
from the path's bounds before the warp to its bounds after it, as they
do under Free Distort. This applies to an object's own Warp and to a
fill's or stroke's own (a stroke uses its stroke-inflated bounds), on
the canvas and in Object > Expand of the fill. In a group with a Warp
effect, each path's and compound path's gradient follows its own
bounds, and the own fills of the group and of the groups inside it
follow those groups' bounds. A warp with no bend and no distortion
leaves gradients exactly where they are, and gradients fitted to the
object are unchanged.

This changes how existing documents draw: a placed gradient on art with
a Warp effect now follows the warped outline instead of staying in
place.

How gradients follow the warp is VectorCraft's own rule. What the Warp
effects do to the object is described in
https://helpx.adobe.com/illustrator/using/reshaping-objects-effects.html
2026-11-08 08:43:27 -08:00
dotCooCoo f51aa41328 Merge main into fix/plugin-grant-module-hash 2026-11-08 08:40:10 -08:00
dotCooCoo 91d9639e6a Plug-ins: a permission grant covers only the module that was approved
A grant records the module's SHA-256, but only its permissions were
compared, so a module with other bytes under a granted id inherited the
grant when it listed no new permission.

A grant now covers a module only when the id, the SHA-256 and every
listed permission match. plugin.inspect reports needsApproval for a
changed module, plugin.install refuses it without a new grant and leaves
the installed module and its grant as they are, Install Plug-in and
File > Open ask again, and the plug-in store and plug-in folders skip it.
The same bytes install again without asking, and a module with no
permissions list or an empty one needs no grant. A grant whose hash is
not 64 lower-case hexadecimal digits covers nothing.

plugin.install still trusts the client that sends grant; the docs say so.
2026-11-08 08:40:00 -08:00
dotCooCoo d485558f44 Plug-ins: Export As leaves out importers' read-only formats
Export As listed every plug-in format, so an importer appeared there and
picking it ended in an error that its files can be opened but not written.
The list now takes only plug-in formats that write. document.formats still
lists importers.

The importer parameters test used the same plug-in id as an exporter test
in the same process. It has an id of its own.
2026-11-08 08:33:34 -08:00
dotCooCoo 5522059417 Save: the save commands and Export for Screens refuse an unknown option key
document.save, file.saveAs, file.saveCopy and file.saveAsTemplate wrote
the file when given a key that no save format reads, beside the path or
in options, or an unknown key inside a PDF option object such as
marks.useDocumentBleed. document.exportForScreens did the same for an
unknown top-level key, a key in a format row and a key in the settings
of a format.

These commands now refuse such a key and name its path
(options.noSuchOption, formats[1].marks.useDocumentBleed). The svg
object is checked in every save, export and format row, also when the
file written is not SVG. A save still leaves out a key that only another
save format reads, and warns as before. A format row and a format's
settings still take includeArtboardFill and richBlack, which the
encoders read. document.exportPresets.save checks its settings, with the
rows and settings in it, the same way.

In the app, file.save and file.exportForScreens sent as commands are
checked as document.save and document.exportForScreens, and app.save is
checked before anything is written; MCP's app.save, file.save and
file.exportForScreens are checked the same way. The SVG Options dialog
no longer passes its internal fields on to the save.
2026-11-08 08:31:24 -08:00
dotCooCoo f3d4233394 Merge main into feat/plugin-importers 2026-11-08 08:15:31 -08:00
dotCooCoo 975c67681c Merge main into fix/spiral-decay-per-wind 2026-11-08 08:13:27 -08:00
M Balazs PC 8f001495ea Merge branch 'fix/ai-type-leading-forced-breaks' into fix/ai-right-aligned-tabs
# Conflicts:
#	docs/file-format-parity.md
#	docs/roadmap.md
#	docs/target-app-parity.md
2026-11-08 17:12:11 +01:00
M Balazs PC 2d47b11624 Merge remote-tracking branch 'origin/main' into fix/ai-type-leading-forced-breaks
# Conflicts:
#	docs/file-format-parity.md
#	docs/roadmap.md
#	docs/target-app-parity.md
2026-11-08 17:11:12 +01:00
dotCooCoo 2772a44efd Plug-ins: Open With runs an importer off the UI thread, and Cancel stops it
File › Open With reads a picked file on the thread File › Open uses, with the importer and its parameters, so a slow importer does not freeze the window. A call that names path still gets document.open's result. Cancel in the progress window now raises a cancel token on that thread, which stops a running importer between two slices of its budget.
2026-11-08 08:09:23 -08:00
HassanKhan d45a538476 Merge remote-tracking branch 'upstream/main' into feat-4936-spell-check
# Conflicts:
#	docs/roadmap.md
#	docs/target-app-parity.md
2026-11-08 21:07:06 +05:00
HassanKhan 1e52ef587d Part of #4936: refuse malformed ids in text.spelling.check; dictionary-independent test; docs
- text.spelling.check checks a given `ids` as edit.findReplace does
  (checked_ids_param): a non-array, a negative, non-numeric or unknown id is
  an error instead of a check of the whole document. Null still means every
  visible, unlocked type object.
- The byte-offset test puts an em dash, not "café", before the unknown word,
  so it passes whichever dictionaries craft-proof is built with (CI builds
  with craft-i18n's, where "café" is unknown).
- Docs: the spell check engine in target-app-parity.md (Type advanced rows
  and evidence), gaps.md (G4), roadmap.md (M7) and the Language per
  character rows of type-parity.md, with status lines and revision history.
2026-11-08 21:01:59 +05:00
FredApps 65adb7b211 Merge pull request #2480 from vangel76/fix/2414-svg-classes
SVG: keep CSS classes of imported elements on export (#2414)
2026-11-08 17:01:22 +01:00
ruchirguitar 04e71eceb8 #5925: merge CI base and target the Layers Filter button by name 2026-11-08 21:26:30 +05:30
FredApps ef4740f6f0 Merge pull request #5284 from vangel76/perf/web-wasm-simd128-2786
Fix #2786: the web build uses WebAssembly SIMD, so the canvas renders about 2.5x faster
2026-11-08 16:54:58 +01:00
dotCooCoo a5ea32b386 Effects: fitted gradients turn with the Transform effect
A gradient fitted to the object refit to the outline after the object's
Transform effect rotated, reflected or scaled it unevenly, so the
gradient kept running left to right while the shape turned under it.
Object › Transform already turns such a gradient.

A Transform effect that a refit would not reproduce now fixes the
gradient to its fit on the geometry the effect takes, and then maps it
with that effect and the effects after it, as a placed gradient. Under
moves and even scales it draws as a refit does, and an effect that
scales the object to nothing across leaves it fitted. This applies to
an object's own effects, a fill's or stroke's own effects, and a
group's: in a group, the gradients fitted to its paths, to its own
fill, to the groups inside it and to its images' and symbol instances'
own fills each fix to the fit on their own object. Object › Expand of
the fill draws the same.

This changes how existing documents draw: art with a fitted gradient
and a Transform effect that rotates, reflects or scales it unevenly
now shows the gradient turned with the art. How gradients follow the
effect is VectorCraft's own rule.
2026-11-08 07:50:26 -08:00
dotCooCoo ca3527e780 Plug-ins: kept rasters over painted pieces follow the swatches and patterns they name
A blur or shadow over a painted piece is drawn again when a swatch or
pattern the piece names is deleted, or when the tiles of a named pattern
change. The raster's inputs now include the swatch and pattern names and
the pattern definitions for content with a plug-in effect.
2026-11-08 07:37:07 -08:00
dotCooCoo edd6acd9c0 Plug-ins: File › Open lists only the importer extensions it opens with an importer
An importer may declare an extension that File › Open handles another
way: a plug-in, shortcut set, script, preset, library or swatch library
such as .ase, or one a built-in format reads. "All readable files" and
the importer's own filter no longer list those extensions, and an
importer with none left gets no filter. Open With still opens them.
2026-11-08 07:31:40 -08:00
dotCooCoo 9f2db12ec2 Plug-ins: a painted live effect's paint keys are checked at every level
A key that a paint does not have, such as `opacity` on a solid fill, was
dropped when the paint was read, and the fill was drawn opaque. The
result is now refused and `lastError` names the field, for keys on the
paint and on its colors, gradient, stops, placement and freeform points.
2026-11-08 07:24:55 -08:00
dotCooCoo 76bb829e3a Graphs: a style that removes a mark's painted row resets the stored opacity
Applying or redefining a graphic style on a series mark whose fill or
stroke had paint, when the style leaves that row without paint, now
stores the row's opacity and blend mode on the graph. Before, the
opacity and blend mode another mark of the series left stayed, so a
Filled Lines band's outline kept a stroke opacity after a style without
a stroke went on a stroked marker. A row with no paint before and after
the edit still keeps what the graph stores.
2026-11-08 06:50:03 -08:00
dotCooCoo 517e0b7ae8 Effects: hiding a 3D effect still checks the values given with it
effect.setParams with visible: false skipped every 3D parameter check,
so a hidden edit could store a Classic depth of 2001, an unknown
surface or bevel, an empty light list or a Revolve edge other than left
or right. The values given are now checked by validate_three_d_params
(the checks of validate_three_d that do not build the art); after a
change of 3D type the values the effect keeps are checked too. The
object still does not need to fit while the effect is hidden.
2026-11-08 06:35:39 -08:00
dotCooCoo f384d27bee 3D (Classic): the solids test checks the classic faces' hue
every_solid_draws_shaded_faces_and_leaves_the_source_editable no longer
skips the color check for Extrude & Bevel (Classic). Its faces must be
the fill's red or the stroke's black, shaded, or lightened toward white
by the Plastic highlight, which keeps r - g to r - b at 6 to 7.
2026-11-08 06:35:38 -08:00
Ahmed Gomaa f12cf9a545 G13: merge main and strengthen snapping regression checks 2026-11-08 16:24:25 +02:00
ruchirguitar 3984874728 M2.1: avoid discarded path copies during deletion (#3380) 2026-11-08 19:35:48 +05:30
M Balazs PC a24ab06c6d Merge branch 'fix/ai-type-leading-forced-breaks' into fix/ai-right-aligned-tabs
# Conflicts:
#	crates/engine/tests/import_fuzz.rs
#	crates/eps/src/import/ate.rs
2026-11-08 14:58:13 +01:00
M Balazs PC f5c3f47612 Merge remote-tracking branch 'origin/main' into fix/ai-type-leading-forced-breaks
# Conflicts:
#	crates/eps/src/import/ate.rs
#	crates/text/src/layout.rs
2026-11-08 14:57:14 +01:00
dotCooCoo b6404f2f8b JavaScript: toLocaleString calls toString on the boxed value, and overwriting an element reserves no heap
Object.prototype.toLocaleString passed the primitive this value to
toString; section 15.2.4.3 calls it on ToObject(this), so a strict
toString now sees the object. The array methods' element write reserved
room for a new element even when it only replaced an own property, so a
heap at its limit stopped reverse or sort writes that add nothing.
2026-11-08 05:54:07 -08:00
dotCooCoo 923faeb35a JavaScript: the test262 interpreter runs fail when a harness file is missing or no test runs
run_tests read an unreadable harness, include or test file as an empty
string, so a broken suite checkout passed with every run counted as a
failure. It now stops with the file's path. The language run checks
that test/language exists, and the language and built-ins runs check
that at least one ES5 test ran.
2026-11-08 05:52:46 -08:00
dotCooCoo d8afed1562 Plug-ins: painted pieces keep their swatches in Pathfinder and baked art
Pathfinder effects, compound shapes, Expand Appearance and pattern
expansion now pass the document to the effects they evaluate, so a
painted piece that names a swatch or pattern takes part as drawn instead
of being refused. A path with a painted effect takes part in Pathfinder
and compound shapes as its pieces, each with its own paint, inside the
path's opacity and blend mode.

The renderer's kept effect art and live evaluations now count the
document's swatch and pattern names for objects with a plug-in effect,
so deleting or restoring a swatch a piece names redraws the object.
2026-11-08 05:52:39 -08:00
dotCooCoo 01c89d4bc5 JavaScript: a small heap limit no longer leaves a realm without built-ins
Installing the built-ins is not bounded by the heap limit: Math and JSON
no longer reserve heap while they install, so a realm made with a tiny
heap_bytes gets every built-in and runs once the limit is raised. If
installing fails, the realm keeps the reason and every run ends with an
internal error instead of running against missing built-ins.

The json2.js test skips only when the built-in check returns false, and
fails on any other result. The parser's progress line says the app does
not run scripts yet.
2026-11-08 05:35:27 -08:00
dotCooCoo d65207dc62 Plug-ins: only File › Open lists importers' files, and imported art at the canvas edge keeps an editable artboard
New from Template, Load Character/Paragraph/All Styles, Recolor's Other
Library… and the library panels' Other Library… read files with the
built-in readers, so their open dialogs now use builtin_open_filters(),
which leaves out the extensions only importer plug-ins read. File › Open
keeps open_filters() with the importers' files.

The artboard of a document an importer opens is now kept within
±4,000,000 pt. Art at the edge (a zero-width path at x = 4,000,000, or a
stroke past the edge) gave an artboard beyond it, and every later edit
of the document was rejected.
2026-11-08 05:35:23 -08:00
dotCooCoo 56f8e3208a i18n: French rows keep the no-break space before punctuation 2026-11-08 05:13:18 -08:00
dotCooCoo 58f5789e9a Plug-ins: Open With passes an importer its parameters and adds the file to Open Recent
File › Open With asks for the parameters of an importer that declares
any, at their defaults, once the file is picked (dialog `pluginImport`),
and opens the file with the values set. `file.openWith`, `app.open` and
MCP's `open_file` take `params` and pass them to the importer;
`app.open` without them runs the importer on their defaults, with no
dialog. A file opened with Open With is added to Open Recent, as File ›
Open adds the files it opens.
2026-11-08 05:07:08 -08:00
dotCooCoo 96bdb813a6 Plug-ins: read-only inputs count toward the input's memory share
A filter's input is now encoded within the half of the plug-in's memory
cap that the input and the parameters share. Every object counts toward
it in paint order, with its id, bounds, transform and name. Type runs
and image pixels that don't fit what is left come with truncated or
pixelsOmitted, and a type, image or symbol instance whose other fields
alone don't fit fails the run before the plug-in starts with
"memory budget (object N needs S bytes of input, L left)".
2026-11-08 04:42:17 -08:00
dotCooCoo 36eec28617 MCP: open_file takes an importer plug-in to open the file with
open_file passes `importer` (an importer plug-in's format id,
plugin.<id>) on to app.open. Headless, it becomes document.open's
`importer`; in the app, app.open with `importer` runs file.openWith, so
the file opens with that importer as File > Open With does, also when a
built-in format reads its extension.
2026-11-08 04:40:23 -08:00
dotCooCoo ca7c0462fb Merge main into fix/ai-writer-object-limit-2 2026-11-08 04:38:21 -08:00
dotCooCoo 9316c17967 .ai save: the editing copy stops at the reader's object limit
The reader stops a whole file past 4,000,000 objects (MAX_NODES), and
the writer had no limit of its own. The writer now counts the objects
it writes as the reader counts them, across layers, symbol and pattern
definitions, opacity masks and art styles, and leaves out art past the
limit with a warning. Art that does not fit is given back as a whole:
a mask, a pattern or a symbol definition is left out with all its art,
and a symbol's definition is written only with room for its instance.
The limit is the reader's own constant, re-exported as
MAX_EDITING_OBJECTS.
2026-11-08 04:38:15 -08:00
dotCooCoo 95678340b0 .ai import: a symbol's linked color named like a color group is renamed
A global or spot color that a symbol library's art links to and whose
name a color group of the document has now comes in under a free variant
of the name, which the art then names, as for a name another swatch has.
Swatches and color groups share one set of names.
2026-11-08 04:34:49 -08:00
Don Omondi 9d706a9a6d Parity doc: paths with an older Art brush keep their drawn look 2026-11-08 06:41:09 -05:00
Don Omondi d87844bba6 Merge remote-tracking branch 'upstream/main' into fix/eps01-editing-overlay
# Conflicts:
#	docs/gaps.md
2026-11-08 06:36:42 -05:00
ruchirguitar 655a16fa67 #5925: add collapse arrows to floating panels and rail flyouts 2026-11-08 17:02:29 +05:30
HassanKhan f71952730f Contributors: Hassan1305's name for the About window 2026-11-08 15:07:37 +05:00
dotCooCoo 7a38e2c990 Merge main into feat/plugin-menu-commands 2026-11-08 02:04:06 -08:00
HassanKhan 7a145576d4 Part of #4936: text.spelling.check lists unknown words, text.spelling.suggest suggests
The Edit > Spelling items have been placeholders with nothing behind them. This adds the
engine half of Check Spelling on craft-proof, the shared spelling engine in craft-libs (at the
revision the other craft-libs crates already pin), so no word list is copied here:

- text.spelling.check {ids?} lists the words the dictionaries don't know in every visible,
  unlocked type object (or ids), each run checked in its Character panel Language (English
  when it has none; nothing in a language without a dictionary), as {id, start, end, word,
  lang}. start/end are byte offsets in the object's text, the ones text.editRange takes, so a
  word is changed with text.editRange as one undo step. At most 10,000 words, with `more`.
- text.spelling.suggest {word, max?, lang?} gives the dictionary's suggestions, asked for one
  word at a time as craft-proof recommends.

English comes from the public-domain Moby word list built into craft-proof. Its dependencies
(log, miniz_oxide, toml, unicode-normalization) are already in the lockfile. The Check
Spelling dialog, Auto Spell Check and Edit Custom Dictionary follow in later PRs.
2026-11-08 14:59:52 +05:00
dotCooCoo 065170b735 Merge main into feat/js-builtins-text 2026-11-08 01:44:20 -08:00
Don Omondi e5674ba1c5 EPS/.ai editing data: test a stack of a solid fill and a stroke without a brush
A path whose style is a solid fill under a 50% Screen stroke comes in as
itself with both, each with its own transparency.
2026-11-08 04:40:55 -05:00
dotCooCoo c66f6b2068 Merge main into fix/export-unknown-options 2026-11-08 01:40:37 -08:00
dotCooCoo f17e700421 Merge main into fix/edit-copy-artboard-route 2026-11-08 01:11:05 -08:00
dotCooCoo 0801e4373f Merge main into feat/js-builtins-core 2026-11-08 01:04:44 -08:00
Don Omondi ba1abb73b0 .ai import: tests for Pattern brushes' number counts and an older Art brush's first number
A Pattern brush reads its scale from 3 or more numbers (the older form's
8 too) and isn't read with fewer; an 8-number Art brush is the older form
whatever its first number. The module notes say the count tells the form.
2026-11-08 03:51:30 -05:00