An Overlapping layer covers the colors above it within its area, so an
area of another color that a shape enclosed was a hole in that shape
and in the shape of every layer around it, and its outline was fitted
once for each of them. In a code-drawn test, a white disc in a black
ring that four grays touch had six copies of its outline.
With Fills and without Create Strokes, each shape is now filled whole,
by a fill rule of VectorCraft's own. The area inside a filled hole is
traced on its own and drawn after the shapes around it, so its outline
is fitted once. An area of one color is drawn from the hole's outline.
A shape keeps a hole where the area holds a transparent pixel or a
color that Ignore Color or Keep Colors leaves out, and a hole smaller
than Noise is filled with the shape's color as before. Nested areas are
traced within a work budget of VectorCraft's own: four times the
image's pixels (counted as at least 65,536) times its colors, each area
costing its box times its colors. An area that costs more than what is
left keeps its holes and is not charged. Create Strokes and outlines
without Fills are unchanged.
Shapes have holes only in those cases, there are more paths, and the
stacking order changes. Expand by Color starts another group of a color
where an area is drawn above the shape around it. The trace's progress
counts finer steps across the rounds of enclosed areas, not one step
per color layer.
A layer's components without its own color are now left out after its
mask is traced, instead of in a labeling pass before it. Every route
finds its components through the same function.
file.close {index} on a tab other than the current one made the
document now at the closed index current and reset the tool, so the
document the user was working in went to the back. The current
document now stays current, found by its id as document.move does, and
its tool keeps its state. Closing the current tab still makes its
neighbor current.
Docs: docs/mcp.md, docs/target-app-parity.md.
Under automation read roots, stroke.arrowheads.list gives `file` as
null for an arrowheads file outside them and names it by its file name
in `error`. stroke.arrowheads.edit and stroke.arrowheads.reload refuse
such a file with the root-check error, naming it by its file name:
edit makes no folder or file and neither opens nor activates the file,
and reload does not read it. Inside the roots, edit opens the file
under the client's roots. The Stroke panel menu is not confined.
An envelope or the Warp effect cuts an image into triangle pieces that
reach a little past their edges, so neighbors overlap and no seams show.
On an image with alpha, the overlap drew that alpha twice: a 50% image
came out about 75% opaque along every cell edge and diagonal.
- The pieces now form a knockout group, and each piece is marked as a
warp piece (`warp_piece`) whose knockout shape is its whole triangle,
so where pieces overlap only the top one draws.
- The canvas knocks each piece out by its triangle at full coverage.
- SVG and PDF draw the pieces of a partly transparent image (its pixels,
opacity, color mask or colorize paint) through one mask each, of the
later triangles that reach it; pixels on a triangle's antialiased edge
come out slightly lighter there. Pieces of an opaque image are drawn
one over another as before.
- SVG writes one copy of the image for pieces cut by opacity masks
(Preserve Shape Using Transparency) too.
- A cell count past the generated-object budget makes an empty group
instead of overflowing.
Docs: docs/target-app-parity.md.
The Color panel and Color Picker cached their out-of-gamut warning and
correction for the last color only. Assigning the document another CMYK
profile, removing it, or changing the working CMYK space in Color
Settings left the old warning showing until the color changed.
The cache entry now also holds the active color settings and the
registered profiles' generation, so the warning is checked again when
either changes. The comments and the color.gamutCheck params text name
the CMYK space actually used: the document's assigned CMYK profile, else
the working CMYK space.
When a document holds two brushes with the same name, the canvas drew
a stroke that names it with the last of them, while brush.get, Brush
Options, expanding, outlining and the SVG, PDF, EPS and .ai exports
took the first. Document Info gave the last one's type, and every row
of that name in the Brushes panel previewed and dragged the last one.
The renderer, Document Info and the Brushes panel now take the first
brush of a name, so the canvas, the panel and the exports agree.
object.expand.info reported a gradient (and a fill) to expand for any
type whose characters have a gradient fill. Expand outlines type first,
and each outline then holds the run's gradient on its own box, so a
gradient that repeats or reflects in more than 256 runs across every
outline stays a gradient: the dialog enabled options that changed
nothing.
- The query now measures the paths type.createOutlines makes of the
glyphs, ruby glyphs and underline and strikethrough bars, each with
its run's paint, and reports a gradient when one of them expands. It
lays the text out only when a run has a gradient fill, stops at the
first outline that expands, and does not change the document. Type in
symbol art, blends and repeats goes through the same check.
- docs/mcp.md says when gradient is false; docs/target-app-parity.md
gets an evidence line.
The Gradient panel's Method menu gets two methods of VectorCraft's own
beside Classic and Perceptual. They mix a linear, radial, conic or
diamond gradient's colors around the hue wheel: hue, saturation and
brightness each change evenly from one stop to the next, and the hue
angle keeps one direction, as the fixed-direction rules of
https://www.w3.org/TR/css-color-4/#hue-interpolation do. Hue Clockwise
lowers the angle (red, magenta, blue), which is clockwise on the color
wheels, and Hue Counterclockwise raises it (red, yellow, green).
Two stops whose hues are less than half a color level apart count as
one hue and keep it, so a color and a tint or shade of it do not turn
the whole wheel. A stop whose RGB numbers are less than half a color
level apart is gray and takes the hue of the stop it mixes with, and
black takes that stop's saturation too.
- `paint.editGradient` and `paint.setFill` take `method: hue-clockwise`
or `hue-counterclockwise`, in any case, with a space or an underscore
for the hyphen or without it; other spellings are an error. The native
file writes `HueClockwise` and `HueCounterclockwise`.
- The canvas and raster exports draw the gradient through stops on its
curve, within half a color level.
- Reverse turns the method the other way with the stops, and a Reflect
spread is repeated from the curve's stops, so both keep the colors.
- SVG and PDF write the gradient as an RGB image, CMYK and spot color
stops included, with the spot warning. EPS writes a shading in process
colors with a warning for spot stops. A legacy .ai file and the .ai
editing data get the colors between the stops as stops of their own,
in process colors, at most 256, with a warning. CSS gets those stops
too.
- The `method` error names the four values, in every catalog.
- The Method menu is as wide as its longest name in the interface
language, within the panel.
Docs: docs/mcp.md, docs/plugins.md, docs/target-app-parity.md, ROADMAP.
PDF export without a PDF/X or PDF/A standard writes pages longer than
200 in at full size in points instead of with a UserUnit scale.
longPagesInPoints is now on by default in PdfSettings, the built-in
presets and the Save PDF dialog. Turning it off writes such a page with a
UserUnit from PDF 1.6 on, as before. PDF/A-2b files keep the UserUnit,
and .ai saves keep it unless longPagesInPoints: true is passed.
Docs: params text, docs/mcp.md, docs/target-app-parity.md.
Three repairs in crates/pathops/src/addons/cleanup.rs grew with the square
of the input. Each now gives the same results as before, bit for bit.
- Collinear anchors: removing an anchor called Vec::remove, so a straight
run of n anchors took O(n^2) moves. The repair now tests each anchor once
against the nearest kept neighbors, with the same test order, neighbors
and stop rule, and moves the kept anchors into place once.
- Nearly Coincident Anchors (near_point_groups): every pair of anchors in
touching grid cells was compared, so a cluster of A anchors cost O(A^2)
checks. Groups now grow one anchor at a time and look only at anchors no
group has taken, by exact position, skipping quarter-cell squares that
lie out of reach.
- Rejoin Path Pieces (rejoin): every pair of ends within the gap was listed
and sorted, O(P^2 log P) for P pieces meeting at one place. Each end now
finds its first partner in the same order (turn, distance, then end
order), searching by direction among the ends still free, and two ends
that are each other's first partner meet.
Tests compare each repair with a copy of the old algorithm on generated
and focused inputs, count the work on dense cases (20,000-anchor runs,
4,000-anchor clusters, 2,000 pieces meeting at one point), and check Health
Check, Show and Fix on a 5,001-anchor path.