The zero point dragged out of the box where the rulers meet snaps as a
Pen or shape tool's point does: with Smart Guides onto the anchors,
centres, edges and paths of the art and the artboards or into line with
them, with Snap to Point onto the anchors and along the ruler guides,
else onto whole pixels or the grid. The guides showing what it snapped
to show during the drag and go when it is released or cancelled
(Escape, focus loss, another document). The origin is still set once,
on release (document.setRulerOrigin, one undo step).
The engine snaps it (Session::ruler_origin_drag, with the tools crate's
rulerguide::OriginDrag over PointSnap::drawn), as it does a guide
dragged out of a ruler.
A new built-in add-on, Image Tools (Object › Plug-ins › Image Tools),
adds Remove Background… (`addon.image.removeBackground`). It makes the
background of the selected images transparent by lowering the alpha of
their own pixels, in one undo step, with no service or model. The
background is the most common color along the image's edges, the
average of the image's corners, or colors the user picks. Contiguous
(on by default) clears it only where it reaches in from an edge; off,
it is cleared wherever it is. Tolerance and Softness (0 to 100, 10 by
default) set how near a color must be to be cleared and the band over
which pixels fade out. Match measures that nearness as the RGB
distance or as the largest difference on one channel. It is a
VectorCraft addition.
- The image stays an image: an embedded PNG with alpha, the source's
ICC profile and resolution, and 16 bits or gray when the source is.
A linked image is embedded and keeps its Placement Options.
- When the edges hold at least as many clear pixels as pixels of their
most common color, edge mode clears nothing, so a second run leaves
the subject alone. Corner mode leaves clear corners out of the
average and clears nothing when all four are clear.
- With Match set to Each Channel, a tolerance of t / 255 × 100 clears
the colors within t 8-bit steps on every channel.
- A CMYK image, a linked image that shows its preview, an image that
would need more than the decode allowance (checked from its header)
and a result with no pixel left are refused, and the document stays
as it was. When no pixel changes, no undo step is added. The result
reports `cleared`, the pixels made fully clear.
- Picked colors are hex colors, with or without `#`, or black, white,
red, green or blue.
- The dialog opens with Preview off; with Preview on, the canvas shows
the result, and Cancel puts the image back. While the dialog
previews, the session keeps the images' decoded pixels (at most
128 MiB, 32 MiB in the web app) so each preview step does not decode
them again, and releases them when the dialog closes with OK or
Cancel. A run that is not a preview step keeps nothing.
Docs: docs/mcp.md (Image Tools add-on), docs/target-app-parity.md.
A library loaded from outside a confined client's read roots keeps its
`loaded/<file name>` id for the session, in ui.inspect, ui.docking and
the library commands, so an id taken from an earlier reply still finds
the same library after another library with the same file name is
loaded. swatch.library.copyToUser leaves out `path` when the file is
outside the read roots, as the saves do.
The ids come from the engine's concealed_library_ids, which now reads a
path written with either separator, counts another platform's absolute
path as outside the roots, and keeps each id in the session.
The grants that should be gone from grants.json but could not be removed
were kept per Session, so a second Session attached to the same Plug-ins
folder in the same process still counted them for plugin.inspect,
plugin.install and loading plug-ins. They are now kept for the process,
by the folder's canonical path and the plug-in id, and a successful
write of grants.json for the id in any session makes the grant count
again. Attaching another folder no longer clears them.
A failed removal does not override a write another session made for
the id in the meantime. The process keeps the latest 256 grant writes
for that check. Another process on the folder still reads grants.json
as it is written.
every_command_survives_empty_params and
read_only_commands_read_the_instance_of_a_picked_object run every command
with {}. That includes plugin.clearCache, which without an id empties the
cache of every plug-in installed in the process. When either sweep ran
during plugin_storage_is_capped_and_survives_a_damaged_settings_file
(called from plugins_keep_settings_and_a_cache_of_their_own_in_the_store),
it deleted that test's cache entries Tile and tile. The test's
st.clear_cache() == MAX_CACHE_BYTES + 3 assertion after the
MAX_CACHE_SCAN folders then failed with 536870912 bytes freed.
Both sweeps now leave plugin.clearCache out.
tests/plugin_clear_cache.rs already runs it with {} in a test binary of
its own. A new test runs the other plug-in commands with {} in the
selection states that every_command_survives_empty_params uses, and checks
that an installed plug-in's cache keeps its 3 bytes.
A script whose first lines name an engine with `#targetengine name` (or
`//@targetengine name`) runs in that engine, and a later script that names
it sees the globals and functions earlier runs left, until the engine is
dropped or the session ends. A script without the line, and
`#targetengine main`, still get a new engine for each run.
- A session keeps at most 8 named engines, each with a 64 MiB heap. A run
that goes past the heap ends with the heap limit, and the engine stays
usable. Names are 1 to 64 bytes. The line comes once, in the script
itself, before its code and its #include lines.
- An uncaught error, a limit or script.stop puts the documents back and
keeps the globals the run set. An internal error drops the engine. A run
stopped at a dialog or left paused ends where it was before the engine
is kept. An error in a function an earlier run defined is reported
without a line and column.
- `vc`, `$`, `alert`, `confirm` and `prompt` are made once for each engine
and act for the run that calls them, including copies an earlier run kept
in a global. `vc.args` gives a read-only copy of the calling run's
`args`, and what a run sets on `$` lasts for that run only.
- `script.engines` lists the named engines with their heap, and
`script.engine.drop {name}` drops one. Scripts cannot run either.
- The engines stay on the thread that made them. A session used on
another thread starts there with no named engines, and the old ones are
dropped on their own thread.
- The web build has no named engines: a run that names one other than
`main` ends with an error before any of it runs.
- `Realm::end` ends a run where it is, `Realm::error_source` counts from
the realm's last script, and `HostItem::FrozenGetter` gives a frozen
value each time it is read.
- The script checker lists `#targetengine` as a supported directive.
Docs: docs/mcp.md, docs/target-app-parity.md, docs/gaps.md.
File › Scripts now lists the .js and .jsx files of the Scripts folder next
to the preferences, each named after its file without the extension, with
each subfolder as a submenu, above Check Script… and Other Script…. The
help page describes this listing:
https://helpx.adobe.com/illustrator/desktop/automate-visualize-data/automate-actions/install-and-run-scripts.html
Choosing a listed script runs it through script.run without the warning
Other Script… shows. script.listInstalled returns the same listing, and
ui.runInstalledScript {path} runs one entry.
VectorCraft's own rules: the folder is read off the UI thread when the
app starts, when its window becomes active and when the File menu of the
window's menu bar opens; only names are read; links, junctions, hidden
and system entries are left out and checked again before a run; one read
stops at 2,048 entries, 512 scripts, 128 subfolders, 4 levels or 250 ms
and the menu then notes that some scripts were not listed. Under an
automation read root, script.listInstalled and ui.menu.list leave out a
folder outside the root.
#1183 (LloydNicholson) also proposed a Scripts menu listing a folder.
Scripts write to a new Script Console with $.write(...values) and
$.writeln(...values), each value as String(value) gives it. vc.log
entries, a run's uncaught error as name:line:column: message, and a
start, end and report line for each run go there too. The report line
gives the run's time, host calls and slowest commands.
- The console keeps at most 2,048 lines and 1 MiB of text, dropping the
oldest and counting what it dropped. A line is cut at 4,096 bytes and
a script's name at 256 bytes, with a count of cut lines. Line feeds,
carriage returns and CRLF break lines; other control characters show
as Unicode Control Pictures.
- script.run's result and scriptReport gain runTimeMs, timingAvailable,
hostCallCounts, slowestCommands and the run's own console. A failed
run's report has them too.
- script.console and script.console.clear read and empty the console;
ui.copyScriptConsole {first?, last?} copies lines as the panel shows
them.
- The panel lays out only the rows in view, selects with click and
Shift-click, and has Clear, Copy Selected and Copy All. Output goes on
while it is closed, and Clear works during a run.
Docs: docs/mcp.md, docs/gaps.md, docs/roadmap.md,
docs/target-app-parity.md.
`Session::history_budget` (default `default_history_budget()`) caps the
memory the undo steps of all open documents keep together. After each
command, tool edit, interaction commit, direct edit, framed script run
and closed undo group, `Session::trim_histories` drops the oldest steps
of any document first, undo steps before redo steps. Each document keeps
its last eight undo steps and next eight redo steps, and a held history
keeps all of its steps. While a script runs or an undo group is open,
no steps are dropped, so a canceled group leaves the other documents'
steps in place. Closing a document frees its share. The steps are not
counted again while neither the budget nor any history changed. Each
document's own `byte_budget` stays as its ceiling.
edit.colorSettings set only the process-wide colour settings, so the RGB and
CMYK working spaces, intent and black point compensation went back to the
defaults at every start, although the profiles color.loadProfile loads are
kept (#2168, #2174). The engine now writes them to a settings file when they
change (Session::attach_color_settings), and the desktop app and
vectorcraft-cli keep that file as `Color Settings.json` next to the
preferences, attached right after the profile store so a saved working space
may be a loaded profile. Saved settings that can't be used (a profile that is
gone, a damaged or oversized file) leave the defaults with a log record, and
the next change writes over them. Nothing is read or written with
VECTORCRAFT_NO_PREFS.
File › Scripts › Other Script… picks a .js or .jsx file, shows a warning
that can be turned off in Preferences › General, and runs the script
against the open documents through the `vc` object. The new
`script.run` and `script.stop` commands run and stop a script over MCP.
- A run is one transaction. Each document it changed gets one undo step
named Run Script. An uncaught error, a limit or a stop puts every
document, the paint, the clipboard, menu state and preferences back.
- A command that fails inside a run, or whose result is too large to
reach the script, is undone and throws an error the script can catch.
- Files a command wrote stay on disk and the report names them, also
when the run is stopped from the quit question.
- While a script runs, other commands that change anything fail with a
busy error; MCP reports it as JSON-RPC error -32003.
- In the app the run advances one slice per frame with a Stop button in
the status bar. A run that adds a great many objects asks whether to
continue; Stop and Escape end it.
- Commands that change state outside the documents, such as prefs.*,
plugin.* and file.place.queue, are refused to scripts.
Docs: docs/mcp.md, docs/gaps.md, docs/roadmap.md,
docs/target-app-parity.md.
text.spelling.addWord, removeWord and changeWord are Check Spelling's Add
and Edit Custom Dictionary's Add, Delete and Change; text.spelling.dictionary
lists the words. They live in craft-proof, which every language's check
reads. The desktop app and vectorcraft-cli keep them in
`Custom Dictionary.txt` next to the preferences (none without preferences);
elsewhere they last until the app closes.
text.spelling.ignoreAll is Ignore All: the active document's checks skip the
word while it is open; not saved, not undoable, and not a change to the
document's revision.
Behaviour: https://helpx.adobe.com/illustrator/desktop/design-with-text/edit-format-text/check-and-correct-spelling.html
When loading the plug-in store can't remove the grant of an id whose stored
module lists no permissions, or can't read grants.json, the entry stays on
disk and still approved the bytes it covers. plugin.install has the same case
when the grant can't be removed and no earlier module can be put back.
The session now keeps those ids and does not count their grants in
plugin.inspect, plugin.install, plugin.reload or a later load of the store. A
successful update of the grant for the id ends that, and so does attaching a
different store.
- A file read for opening is laid out in the composite fonts registered
then. Opening a document and reverting the front one now measure again
the type set in a font named like a composite font that an open document
defines, the font database holds or the session registered earlier. Type
in other fonts, missing ones included, keeps the bounds it was read with.
- Switching to a document or closing the front one measures again the type
set in a composite font whose definition changed, and any type without
bounds.
- A document reverted while in the back measures its type in composite
fonts when it comes to the front, not in the front document's.
- Text holding an inline graphic whose symbol's type was measured again
takes the graphic's new size.
- A failed or panicked command puts the font database's composite fonts
back with the documents.
- Setting a composite font to the definition an export lends keeps it after
the export ends.
`plugin.install` accepted `grant` and `allowHeavy` from any client, so
the program installing a plug-in could answer its own permission
prompt.
The desktop app now shows an approval dialog that names the module,
its hash and what it asks for. Confirming it gives the engine a
one-use approval tied to that module id, hash and permission list. A
control or MCP request and a frame of synthetic input cannot confirm
the dialog, and Enter does not confirm it.
Without such an approval, `grant` and `allowHeavy` are refused. The
new `--allow-plugin-grants` flag on `mcp` and `run` lets a person who
starts a headless session accept them from requests. The flag cannot
be combined with `--connect`. A module already approved in the desktop
app still installs through its stored grant.
The remembered selection is now tied to the document it was made in, by its
uid, instead of being cleared on every tool reset: another view of the same
document, or closing an inactive tab, kept the anchors picked but made Copy
take the whole path.
A lent gesture that leaves the selection as it found it (a Cmd+Shift marquee
over nothing) is no longer recorded as a pick, so the Pen's last anchor stays
its own and Copy takes the whole path.
Also records #6123 in target-app-parity.md.
With the Pen or Curvature tool, Copy and Cut ignore the anchor selection,
so that the last anchor the Pen leaves selected doesn't make Copy take just
that anchor (#2122). Anchors picked with the Direct Selection that Cmd/Ctrl
lends those tools were ignored too, and the whole path was copied.
The session now remembers the selection the lent tool leaves when it gives
the tool back. While that is still the selection, Copy and Cut take the
picked anchors and segments, as with Direct Selection chosen.