When a Smooth tool drag refits the stretch at the first or last anchor
of an open path, the curve there now leaves or arrives along the
smoothed path within the tool's reach instead of along the first or
last segment, so a jagged end no longer keeps its jag. The end point
stays where it is. An end where the smoothed path turns back by 90
degrees or more keeps its segment's direction, and a stretch that ends
inside the path keeps the direction of the part outside the drag.
- pathops: SimplifyOptions gains free_start and free_end, off by
default; closed subpaths and simplify_part ignore them, so Simplify
and Object > Path > Smooth give the same output as before.
- engine: path.smoothRegion sets them for the ends of an open path
that a run's refit reaches.
Docs: docs/mcp.md, docs/target-app-parity.md.
An SVG or SVGZ writes each linked JavaScript file of SVG Interactivity
into a <script xlink:href> element as stored, so a caller with
automation read roots could read a path outside them from the exported
text. With read roots in force, an SVG or SVGZ of a document that links
such a file is now refused with "a linked JavaScript file is outside the
read roots", an error that names no file or folder. No file or folder is
written, and the document keeps the link.
- The check uses the rule document.json already applies to
svg_scripts: a relative path is taken from the document's folder, a
file: URL is a file, and another URL is not checked.
- It covers document.serialize, document.export, document.exportSelection,
document.exportForScreens and assets.export (before the folder is made
or any row is written), the SVG and SVGZ saves (also a save without a
path of a document saved as SVG), file.exportAs and the SVG Options
dialog's Show Code.
- Callers without roots, and the person at the keyboard, export the
links as stored.
Docs: docs/mcp.md, docs/target-app-parity.md.
The panel showed the values Document Info makes in English in every
language. It now shows the Units, the Raster Effects resolution, each
font's file, substitution and embedding permission, each image's size
and linked file, each Repeat object's kind and counts (in the
language's plural forms) and gradients named by their kind in the
interface language. Font, face, file and swatch names stay as they
are, a gradient swatch named like a kind included.
document.info keeps its English rows and adds the values the panel
builds them from: document.unitId, fontDetails, imageObjects and a
kinds list on each gradientObjects entry. Save… and Package's report
stay in English.
The outline of the area a Blob Brush or Eraser drag covers was outlined
again for the whole stroke on every frame, so a long stroke slowed the
canvas as it grew.
- The drag is outlined in pieces of up to 32 segments (one segment each
with Size set to Pressure), and a frame outlines again only the pieces
it added segments to. A grid of squares lists the segments near each
square, and each piece's outline drops the parts inside the rest of
the area, so the pieces show as one edge.
- One frame takes at most 256 new points and a fixed amount of work;
Tool::overlays_pending makes the canvas draw again until the rest is
done with the pointer still. Points not outlined yet show as a thin
line, and the tip shows at the pointer.
- The settled outline is kept in joined paths of 64 pieces, and a frame
joins again only the paths that changed. The grid's size is capped.
- The Blob Brush's length label and the Size-by-pressure check keep
running values instead of rescanning the stroke each frame. With Size
set to Pressure the outline shows only the edge of the whole area.
The release sends the same path.blob and path.eraseRegion parameters.
A fill or stroke row that the Appearance commands gave a graph label, its
object opacity, and the characters the Eyedropper gave it lasted only
until the graph was drawn again: the graph stored nothing for a label's
rows, and the Eyedropper's character attributes were not stored.
- The graph keeps, for value axis numbers, category labels and legend
labels, the paint, weight, opacity and blend mode of a label's topmost
visible fill and stroke row, their order and place relative to the
Characters row, and the label's object opacity and blend mode
(labelStyles valuesRows, categoriesRows, legendRows). Every label of
the kind gets those rows when the graph is drawn again, with a placed
gradient fitted to each label.
- Every appearance.* command stores them, and so do graphicStyle.apply
and redefine and the paint, stroke, gradient and transparency edits
aimed at a row, even when the label already showed them.
transparency.set without a row and object.setProps store only the
object opacity and blend mode. With several labels of a kind, the last
one edited wins.
- appearance.copyFrom onto all of a label's text stores the character
attributes it applied and, from type, the paragraph attributes; a
transparency pick stores the object opacity and blend mode, and
append stores the rows.
- paint.setFill and paint.setStroke store a character fill or stroke
only when the characters take the paint (the whole label, or all of
its text highlighted with the Type tool); aimed at a row, they store
the row.
- Document Color Mode and swatch edits reach the kept rows.
Docs: docs/mcp.md, the commands' params text, docs/target-app-parity.md.
tool.setOption for the Live Paint Bucket, the Live Paint Selection tool
and the Shape Builder used to keep the old value when a switch was not
true or false, a color could not be read or a width or gap length was
not a number, and it set the other values sent with it. It also took
the RGB of a color with an alpha part, and the Shape Builder took any
`pickColorFrom` other than `swatches` as `artwork` and any `selection`
other than `straightLine` as `freeform`.
The command now checks every value before it sets any, whether the tool
is chosen or not: a switch must be true or false, a highlight color
must be an RGB color or a layer color's name without an alpha part, a
width or gap length must be a number, `pickColorFrom` and `selection`
must be one of their names, and an option the tool does not have is an
error. The error names the option, and nothing is set or saved. A width
outside 1 to 20 and a gap length outside 0 to 72 are still clamped, and
saved settings with an invalid value still load.
Docs: docs/mcp.md, docs/target-app-parity.md.
Giving the keys of a blend whose spine came from Replace Spine anchors of
their own flattened and measured the whole spine again for every key,
then walked its segments one by one. 1,000 keys on a spine of 4,096
segments flattened it 999 times.
The spine is now flattened once into one buffer. A split flattens only
its two halves and measures the segments after it again, in order, only
as far as the next key, so the arc lengths are summed as before and the
keys get the same anchors. A binary search finds each key's segment.
A spine so large that its length overflows no longer gets an anchor
split at a parameter that is not a number: spreading keys along it
returns nothing and leaves it as it was.
A path or compound path with straight segments and nothing stroked was
read with its Twist live at any angle. It is now read live up to 180°
either way, a limit VectorCraft sets, and one twisted further keeps the
file's drawn look, as curves and groups already do past 90°.
The .ai writer keeps a graphic-style link only where the reader reads the
style live, so a straight object twisted past 180° is now written without
the link, with the existing style-link warning.
Docs: docs/file-format-parity.md, docs/target-app-parity.md.
A command now counts as taking a file or folder when its params
description (with the commands its `…` entries name) or its schema takes
a file key as a param. A word in the description's prose or result no
longer counts; a description whose keys are not known keeps the text
scan. The code of the call-time scan of arguments is unchanged, but it
reads the changed exemption tables. The confined run is unchanged.
- NOT_FILES drops seven entries that named no param of their command
(object.setLiveShape path, path.reverse paths, object.pathfinder.options
paths, object.maskImage path, imageTrace.make paths,
svgInteractivity.info files, addon.cleanup.rejoin paths). A top-level
`path` to object.setLiveShape or object.maskImage, `paths` to
path.reverse, imageTrace.make or addon.cleanup.rejoin, and `files` to
svgInteractivity.info are now refused.
- Image Trace's path fidelity setting is exempt only inside `params` and
`savedPreset` of imageTrace.make and imageTrace.makeAndExpand, so a
call with it is no longer refused.
- every_command_is_sorted checks that each exemption names a param its
command takes, and that each nested exemption starts at one.
- effect.expandAsWireframes is reviewed as allowed and
stroke.arrowheads.list as refused.
stops and stop flattened the path twice, once for the points and once
for its length, and stop did both before rejecting an index past the
last object. place validated the path with attachable_path first, and
transform measured the old and new paths up to three times each.
A private Measured value now holds the flattened first subpath with its
length and closed flag, and path_length, stops, stop and transform use
it. stop returns None for an out-of-range index without measuring, and
a move of the group measures no path.
attachable_path now uses path_length, so a path whose length overflows
to infinity is no longer offered as one objects can attach to when
placement cannot measure it.
A Smooth drag along the middle of a curved segment smoothed nothing when
neither of the segment's anchors was within the reach, and paths of two
anchors were never smoothed.
- path.smoothRegion searches each curved segment where it can come
within the reach, halving it down to pieces no longer than half the
reach, and adds an anchor in the middle of each stretch in reach; the
existing reach split then cuts the segment where the drag enters and
leaves the reach. A drag that only grazes a curve finds the place on
it nearest the drag. The search is bounded per drag and shared
equally by the segments in reach.
- Paths of two anchors are smoothed, open or closed.
- Alt with the Paintbrush smooths a selected two-anchor curve; a
two-anchor straight line still gets the closed stroke. Both sides use
one segment_is_straight test.
Part of #2224
- The clipping path of a clip group or a clipped layer takes no part,
the members of a compound clipping path included. Before, only a
plain clipping path was left out.
- In isolation mode only paths inside the isolated object are trimmed;
paths outside it still count as crossing.
- A rectangle or line that reaches so many paths that comparing their
boxes would take more than 50,000,000 tests is refused before any
work starts.
- A tool drag that goes 3 screen pixels or more from the press stays a
rectangle or line when it ends near the press. Before, it ran as a
click and could remove a whole path the final rectangle did not
touch.
Docs: docs/mcp.md.
The current File formats rows of docs/target-app-parity.md now name the legacy .ai manual kerning, discretionary hyphen and hyphenation language reading and writing, with their tests. Score, gaps and hours are unchanged.