With Invert Wrap, each piece of a line's band intersected the line's
spans so far with the spans the wrap shape holds over that piece by
comparing every pair of them. A wrap shape of many parts (a comb or a
zigzag) gives a line many spans, and with an offset the band is cut
into up to 128 pieces, so a dense shape made layout quadratic in the
number of parts for every line.
intersect_intervals now walks the two sorted lists once, stepping past
whichever interval ends first, and gives the same spans in the same
order. Tests compare it with the pairwise intersection on every list of
non-overlapping intervals with ends among seven points, check that two
interleaved lists of 3,000 and 2,000 intervals take at most 5,000
steps, and lay out a line inside a 500-tooth Invert Wrap comb with an
offset.
Spot Color Objects listed every spot color linked from a gradient's stops
once any stop was above opacity 0. A spot stop at opacity 0 between other
clear stops, at the end of the ramp after a clear stop, or meeting an
opaque stop only at one offset was listed though it prints no ink, and so
was an opaque stop out of order whose pairs have no width.
A stop now counts when it bounds a stretch of some width that the
gradient sampler mixes and either stop of that stretch is above opacity
0, or when it is the first or last stop and above opacity 0, since those
color the offsets before and after the others. Stops in any order are
judged by the stretches the sampler uses. A freeform gradient keeps the
old rule, since it draws from its points. Type runs follow the same rule.
The document.info params text, docs/mcp.md and the progress line
describe it.
In a PDF without a standard, the warning for a page longer than 14,400 pt
written with a UserUnit above 1 now ends with "turn on Write pages longer
than 200 in at full size in points". The warning already said that apps
ignoring UserUnit show such a page smaller; it now names the Save PDF
option that writes the page at its size in points instead. PDF/A files,
which keep the UserUnit with the option on, and .ai saves, whose options
do not have it, keep the warning as it was.
The longer message has a row in every complete-message catalog. The
params text of document.exportPdf, docs/mcp.md and the evidence line in
docs/target-app-parity.md describe it.
object.distort warped the anchors of paths, groups, compound paths and
clip groups but left their bounding-box angle as it was, so a rotated
path kept its old box after a warp and an upright one stayed square to
the page however far the warp tilted it. Text, images and symbol
instances already took the angle of the warp's affine approximation.
- Each path, group, compound path and clip group now takes the angle
the warp turns its x axis to at its own center before the warp, the
members of a warped group and the art of a linked opacity mask each
at their own. An unlinked mask's art keeps its angle. Mirroring keeps
the nearer angle and a collapsing warp keeps the old one. Reset
Bounding Box squares the boxes again.
- Each subtree's bounds are measured once while it is warped.
- Corners that equal the corners of the box being warped change
nothing and add no undo step.
Docs: object.distort params text, docs/mcp.md, docs/target-app-parity.md.
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.