The enabled check of artboard.deleteEmpty built the full list of empty
artboards, measuring the visual bounds of the art against every
artboard, each time the Artboards panel menu was drawn. It now returns
false at once in a document with one artboard (that artboard is never
deleted). With two or more, it asks the new
Document::any_artboard_without_art whether any unlocked artboard has no
art, which is the same answer as a non-empty list.
Document::any_artboard_without_art builds the symbol boxes once for all
the artboards and first tests each path and compound path by a quick
box: its control points' box grown by the farthest its strokes reach
(Appearance::outset), with a margin for rounding. An artboard that no
quick box meets is reported empty without measuring along any path.
Only when every artboard may hold art is each one measured.
Document::artboard_has_art also skips measuring an object whose quick
box misses the artboard; its answers are unchanged.
The check of gradient.presets.save found the proxy paints through
Node::proxy_paint, which measures the object's geometric bounds for a
gradient box the check does not use. Node::proxy_paint_only picks the
same paint without measuring, and the engine's proxy_paint uses it, so
the Fill and Stroke proxies and the mixed-paint test no longer measure
each object either.
With an open stroked path of 200,000 anchors selected, the two checks
take under 0.01 ms instead of 21.9 ms and 17.2 ms in a release build, and
Delete Empty Artboards' check takes 0.85 ms instead of 42.1 ms with a
second, empty artboard.
Tests compare each check with what its command does (one artboard, all
empty, one empty, locked empty, nested art; with and without a
gradient), compare any_empty_artboards with the previous check and with
measuring every object on 120 seeded documents, compare the quick boxes
with the visual bounds on seeded strokes, and compare proxy_paint_only
with proxy_paint on seeded objects.
Docs: docs/target-app-parity.md, one line under Delete Empty Artboards.
An instance of a symbol whose art holds a 9-slice instance draws that
instance through its guides with the transform of every instance above
it. When the outer symbol has no guides, the quick box of an outer
instance that scales or turns its art was its art box placed by its
transform, and the renderer could cull art the nested guides move past
that box.
Symbol art boxes now record whether the art holds an instance of a
symbol with 9-slice guides at any depth. For such art, quick boxes
place the art by the instance's transform and measure it, once for each
symbol and linear part. One set of boxes places at most
MAX_SYMBOL_NODES objects this way, the art of opacity masks included.
An object in 9-slice art that crosses a guide and draws symbol art is
placed by the map of the cell its center is in, so it can draw outside
the instance's transformed art box. Bounds measured without placing the
art (the renderer's culling, and placements past the object limit) used
that box alone, so the displaced art could be culled and not drawn.
The fallback now takes in the art box placed by each of the nine cells'
maps (NineSliceMap::placement_bounds), grown by the art's reach as
before.
A compound path was assembled from its members in every frame it was
drawn, and Node::stroke_path grew its buffer by doubling, copying the
path into ever larger buffers for a compound path of many anchors. The
renderer's geometry cache was swept only once it held more than 1,024
entries, so while an object was dragged (a new node, and layer, in
every frame) the old copies stayed alive with all their members.
Now:
- a compound path is drawn from the path the renderer keeps for it in
its geometry cache, as a plain path already was, and is assembled
only when the node changes;
- Node::stroke_path sizes a compound path's buffer up front from its
members' segment counts (the same elements, in the same order);
- unused geometry entries are dropped after a few frames however few
entries there are.
Tests:
- crates/render/src/tests/memory.rs: the second frame draws the kept
path and the same pixels as the first and as a new renderer; after a
five-frame move the renderer no longer holds the compound path drawn
before it. The test fails without the renderer change.
- crates/doc/src/node/tests.rs: a compound path's path is its members'
paths in order (open, closed, empty and single-anchor members).
Not timed; vectorcraft-cli perf was not rerun.
With one Objects on Path group of two or more objects selected, the
Selection and Objects on Path tools show a square Space widget beyond the
last object, ahead along the path. Dragging it moves the last object
along the path, around its bends, as far as the pointer moves along it,
and the objects between follow evenly while the first one stays. With
Alt (Option on macOS) the objects spread from both ends toward or away
from the center of an open path, or of the first anchor of a closed one.
The distance between the objects shows next to the pointer in the
document's units; the drag is one undo step, and Escape cancels it.
- object.objectsOnPath.options takes spacing (points, or "auto", the
default even spread) and start (points from the first anchor). A
spacing the path has no room for is drawn smaller and kept, so a
longer path brings it back. Older files read as Auto.
- Moving the group, Pivot, Rotate, path edits, copies and saving keep
the Space. Scaling, rotating or shearing the group keeps the first
and last objects where the transform takes them on the new path, live
shapes included; a value that cannot be kept that way scales with the
path's length.
- The Rotate All widget follows the first object when Space moves it.
Behavior: https://helpx.adobe.com/illustrator/desktop/manage-objects/arrange-objects/rearrange-and-edit-objects-on-a-path.html
and https://helpx.adobe.com/illustrator/using/objects-on-path.html.
Flattening counted every colorized image as transparency, in the art and
in pattern tiles. A new flattener option, keeps_colorize, stops counting
an image colorized with a solid paint whose pixels are grayscale or 1-bit,
for a format whose writer draws such images in their ink. Opacity,
blending modes, opacity masks and effects still flatten them, and pattern
tiles are still expanded for those. The option is off, so exports flatten
as before; the EPS writer that draws colorized images turns it on.
The EPS pattern tile tests now check the exported colors, and a tile
group with opacity for the warning.
A colorized grayscale or 1-bit image draws its white pixels transparent and is written to
PDF with the image as a soft mask. Node::shows_transparency did not count it, so a PDF 1.3,
PDF/X-1a or PDF/X-3 export whose only transparency was a colorized image was not flattened
and kept the soft mask. A legacy .ai save also wrote such an image as opaque.
- shows_transparency counts a visible image with a colorize paint.
- The legacy .ai writer flattens or leaves out colorized images like other see-through images.