A live-effect plug-in that paints its pieces draws each piece's brushed
stroke along the piece's path at the piece's stroke width. Culling left
room for brush art from the object's own stroke width around the
pieces, so brush art of a moved or wider piece was cut off at the edge
of the view. Culling now leaves 16 x the piece's stroke width + 8 pt
past each brushed piece, and does so for a symbol instance whose art
holds such a path (measured once per symbol) and for a blend, envelope
or repeat that holds one. Object > Rasterize measures the brush art
drawn along each piece and leaves out the object's own brush art, which
is not drawn.
Groups and layers now leave room for their members' brush art. The
cull bounds of a group or layer united its members' bounds without the
room each brushed member leaves, so the painted bounds of a group, and
the area redrawn when it changes, left out brush art past its members'
strokes. That applied to plain brushed paths as well as painted pieces.
Each member is now measured as the renderer measures it when it draws
the group, in the members of a group with a fill, stroke or adjustment
of its own and in a group with crop marks or Vector Halftone too.
A geometry effect on a symbol instance's topmost fill now reshapes the
filled shapes of the symbol's art, and one on its topmost stroke reshapes
the stroked shapes, keeping their colors, strokes and other detail. Only
a visible topmost fill or stroke with an opacity above 0 counts. Clipping
paths, guides and opacity-mask art keep their shapes; a group's own fills
and strokes in the art take the effects; a nested instance passes them on
to its own art, except one whose symbol holds the outer symbol.
The canvas, Use Preview Bounds and the drawn bounds, SVG and PDF export
and Object > Expand Appearance use the same art. Expand Appearance is
enabled for such an instance and turns it into an editable group in one
undo step. Bounds measure the art with a dynamic symbol's overrides, as
the canvas draws it.
Existing documents with a geometry effect on a symbol instance's fill or
stroke draw differently: before, the effect drew nothing.
A Transform effect on a group reshaped its members' paths but left the
raster effects inside it at their own values: a member's Drop Shadow
kept its 10 pt offset under a 200% Transform effect, and with Scale
Strokes & Effects on, it scaled by the mean scale without turning. The
same held for the raster effects of an object's own fills and strokes
under the object's Transform effect.
- A Transform effect that moves the art once now transforms the raster
effects of a group's members (their own and their fills' and
strokes'), of nested groups, of the art of the linked opacity masks
in it and of an object's fills and strokes, after the members' own
Transform effects: sizes scale by the mean scale and a Drop Shadow's
offset turns, reflects and scales. A raster effect that a member's
own Transform effect with copies or random holds back keeps its value
through that effect and still transforms with the group's. Scale
Strokes & Effects does not scale them a second time. A group's or
object's Transform effect that makes copies or moves at random leaves
them as before.
- The canvas, the redraw region, export, Expand Appearance, Object ›
Expand and Outline Stroke read the same values.
- The Transform effect's params text and docs/target-app-parity.md
describe the rule.
When the document does not hold a color mask's masked pixels, the image is
drawn from its own pixels. A live color adjustment now recolors those pixels
and drops the mask on the recolored copy, instead of pointing the image at
the missing masked pixels, which drew nothing and left Expand Appearance with
an image whose pixels were not in the document.
The canvas kept the art of an image whose own fill or stroke follows the
outline of its pixels for as long as the image object stayed the same. When
the document's pixels for the image changed under the same key (Update Link
replacing a preview with the linked file's pixels), the stroke kept the old
outline while hit testing and Use Preview Bounds used the new one. The
renderer now keys that art by the document's pixels for the image too.
- vectorcraft-effects: `follows_image_pixels` names such images.
- vectorcraft-render: `reads_outside` counts them, and the resources key
hashes the address of the document's pixels for them; their walk is not
kept between frames.
- A test places an off-center opaque area in a smaller copy of the pixels
under a turned and reflected placement.
- Docs: the Outline Object params text names every case that keeps the frame
and the 50% cutoff as VectorCraft's own; docs/mcp.md's `effect.apply` entry
for Outline Object, how long an outline is kept and the 16-bit RGBA limit;
docs/target-app-parity.md's evidence lines.
An object with an opacity mask draws offscreen over the bounds the
renderer gives it. For a live object (a blend, envelope or repeat) those
bounds took in effects in symbol art and brush art inside it, but not a
path's own effects, so with Clip off the drop shadows of a blend's steps
were cut off at the steps' bounds and did not draw where the mask art
leaves them uncovered. The bounds now also take in how far each path's
own effects paint past it.
Effects apply in the order they are listed, so a Drop Shadow, glow, blur,
Feather or pixel filter listed before a Transform effect paints art that
the Transform effect then transforms. VectorCraft drew such an
effect at its own distances around the transformed art: a square scaled
to 200% kept a 10 pt shadow offset. Now the effect follows the Transform
effects after it, with Scale Strokes & Effects on or off: its sizes scale
by the mean scale, and a Drop Shadow's offset turns, reflects and scales
with the art. Effects listed after the Transform effect keep their values,
and Transform Objects off changes nothing.
- raster_effects reads each raster effect through the Transform effects
after it, so the canvas, export and the redraw region use the followed
values.
- Where the geometry effects are applied and removed (Expand Appearance,
baking for export, evaluated groups), the raster effects that remain
carry the same transformation, hidden ones included.
- A Transform effect that makes copies or moves at random leaves the
raster effects before it as they are. Rasterize and SVG filters keep
their options.
Docs: the Transform effect's params text, docs/target-app-parity.md.
- Resolving the symbol instances, blends and clipping groups a 3D effect
builds from counts every object it visits or makes and stops past
262,144 with an error. Nested symbol instances that end in hidden art
are refused instead of being expanded at every level. Each object is
visited once; a group is no longer walked again for each level above it.
- A symbol instance, blend or clipping group inside a 3D group keeps its
appearance, so its geometry effects reshape the art it shows. A nested
group's geometry effects now reshape its members inside a 3D group too,
and inside a clipping group they apply before the clip cuts the art.
- Hidden members and guides of a group inside a clipping group build no
solid.
- Tests cover an empty clipping group, a blend set to no steps, an
instance of an empty symbol, a symbol holding a clipping group, the
paint-copy budget across resolved art, and art past the limits drawing
as it does without the effect.
Extrude & Bevel, Extrude & Bevel (Classic), Inflate, Rotate and Revolve
now apply to a clipping group (or a layer with a clipping mask), a blend
or a symbol instance, alone or inside a group or layer. The solid is
built from the art the object shows: the art inside the clipping path
(fills cut to the clip, strokes as their outlines cut to the clip), the
blend's keys and steps, and the symbol's art where the instance places
it. Validation, the canvas, bounds, Expand Appearance, Rasterize and
assets.add3D read the same art from the document.
An image is refused, alone or in a group, with a message to trace it
first with Object > Image Trace > Make. A missing symbol, a symbol that
holds an instance of itself, art nested more than 64 levels deep and
more than 4,096 objects are refused. The refusal messages change, and
their rows change in every catalog.
Docs: docs/three-d.md, docs/revolve.md, docs/mcp.md,
docs/target-app-parity.md.
a_coarser_glow_kept_whole_draws_after_a_pan_as_made_again compared only
whole-pixel pans with a fresh render. At a fractional pan it now compares
the pixels right of the rectangle, where only the glow draws, with a fresh
render at the whole pixel nearest the pan (either neighbor on a half pixel).
RenderOptions::background and render_node_thumbnail's background are
straight-alpha colors, as over_background reads them; their docs said
premultiplied.
Type sweeps as its glyph outlines and stays editable. On a group or layer every visible member sweeps about one axis on the edge of the members' bounds together, each in its own paint.
A surface now takes up to 16,384 profile points and 163,840 faces. Curves take fewer samples, down to 4, when a surface passes those limits, and the command reports the failure below that, after the geometry effects before the Revolve and with the cumulative size of its paint copies counted. Mesh export turns the walls of holes toward them. Expand Appearance works on type with Extrude as well as Revolve.
Fixes#3617
A new test changes the document in place (Arc::make_mut, with no other
holder and no change of revision) and checks the answer is measured
again: keyed on the document's address alone, it would keep the old
answer. The kept answer's doc says what it holds after the measure,
and that the fonts set the bounds of all type. Should measuring ever
ask again while it runs, it is measured without being kept, rather
than borrowed twice.
The stack overflow fixed in d5d04f868 also hit EPS export, and the
parity rows now say so. Two test docs are corrected: the fill-only
clipping is an older bug on main, and the outline-view difference runs
both ways on a few dozen hairline pixels.
- The parity rows say what the fix covers: a 3D effect on a fill or
stroke that builds nothing overflowed the stack with no effect of the
object's own too, on the canvas, in Object › Rasterize and in raster
exports.
- The builds-nothing test says the fill-only difference (a raster
effect clipped to the path, cutting Roughen's spikes, when drawn
without the 3D effect) is an older bug, not the design.
- The traced-shape test says why its area is bounded rather than drawn
again: a partial render in outline view differs from the whole by one
in alpha on 37 pixels, older than the test and unrelated to the edit.
- A doc comment rewrapped.
Flatten Transparency composited each region over white, so a blend mode
on the bare page read that white. Raster renders now draw their
background under the finished art, and the flattened color no longer
matched them: a Color Burn object on the bare page flattened to white
and rendered in its own color. The region now composites the art alone
and puts the white under it.
- Tests that relied on the white under the art now draw art under the
style (`every_builtin_style_paints_visibly_on_a_rectangle`) or compare
only whole-pixel pans with a fresh render
(`a_coarser_glow_kept_whole_draws_after_a_pan_as_made_again`).
- New tests cover every blend mode on white and blue backgrounds, a
thumbnail and the ink planes with a Screen glow, and
`over_background` at background and pixel alpha 0, 128 and 255.
- A 3D effect that builds nothing: af754bcb2 said the object draws exactly
as without it under a Drop Shadow or Gaussian Blur. That holds only for
a stroked object. With only a fill, the raster effect draws from the
art made for the object, where without the 3D effect it is clipped to
the path, so Roughen's spikes differ: the earlier wording was right.
The test keeps the stroked cases exact and restores fill-only cases
with a Drop Shadow and a Gaussian Blur, which differ in under 4% of
the pixels and nowhere inside the path. Its reach check compares with
the object drawn without its raster effect, since Roughen alone
reaches past the path.
- The Vector Halftone test's bounds are a consistency check, and only
holding no art tests the branch: its doc no longer says no solid is
built (the free measure's halftone arm builds one). The overprint
test's area check is labeled likewise.
- Recoloring a traced shape bounds the area the renderer that drew the
trace object measures too, inflated by half the stroke and a pixel.
- The let-go test pins the nothing-to-draw branch: no frame, whole or
part, began since the measure.
- The parity doc's feature row names the stack overflow fix and its
test; a group test's doc says what its fixture holds.
Review follow-ups:
- The tests that a group with effects of its own is measured once a pass
plant its kept bounds after the first artboard and read them back over
the next two, so a measure made again fails. Its solid is built by the
free measure, which the renderer's three_d_built doesn't count.
- The budget test checks that every object, past the budget too, is
measured as the free measure does and draws as a new renderer draws it.
- A 3D effect that builds nothing draws the object exactly as without it,
with a Drop Shadow or Gaussian Blur too, which reach past the path. The
doc comment said those differ past the path; they don't.
- The brush widened in view first checks that the wider brush draws
otherwise.
- Recoloring a traced shape changes no more than the shape, its stroke
and a pixel's anti-aliasing.
Review follow-up: these three branches of what a renderer measures had no
test. Under Overprint Preview a renderer measures an edit as changed()
does and holds none of the 3D art it made for it; a 3D effect with
Vector Halftone is measured by the free measure, with no solid built and
no art held; and on screen in symbol editing mode, an edit to the
instance it was entered from changes nothing. Each test fails with its
branch taken out.
Review of #6290.
- An Image Trace object's hidden source image counts as shown in each
version by that version's own first member: an edit that puts it
first again (undoing Send to Back on a traced shape), or a new source
image in its place, redraws where it shows. Tested with an image
source on screen with the objects' views.
- A shape of an Image Trace object in Outline view is left out by the
rule every object is (node_checks::left_out), so the drawing and the
measure of an edit can't disagree.
- The renderer keeps the brush library's key from its first measure of
3D art until the library changes; the test says so, and that a change
lets it go.
- The test of a 3D effect that builds nothing covers it on a fill and
on a stroke, without effects of the object's own (exactly as without
it) and under a raster effect.
On the commit before, "Canvas: a 3D effect on a fill that builds nothing
draws without it": it needs no effect of the object's own. A 3D effect
on a fill or stroke that builds nothing overflowed the stack on its own
too. With a raster effect, the object now draws from its art, where
without the 3D effect it draws as a path, whose raster effects are
clipped to the path's own geometry, cutting off the item's Roughen
spikes: the new drawing is the one that keeps them.
An object with an effect of its own (Drop Shadow, Roughen) and a 3D
effect on its fill or stroke that builds nothing (Revolve after
Roughen, a solid too complex) overflowed the stack when drawn, on the
canvas and in Object › Rasterize: the art made for the object kept the
item's 3D effect, so drawing it drew it as an object with effects again,
and that art again, without end.
That art now leaves out the 3D effects on its fills and strokes when
none built anything, as a group's or layer's own are left to the art of
each fill or stroke. The fill draws as without the effect; with a raster
effect the object draws from that art, so its edges differ a little
from the same object without the 3D effect, drawn as a path.
Review of #6290.
- An edit is measured as the renderer draws: an object it leaves out
(hidden, a template layer or guide the view hides, drawn hidden, the
instance a symbol is edited from) is measured as nothing, by one
predicate the renderer and the measure share (node_checks::left_out,
before culling).
- An Image Trace object's members are compared one by one again, its
hidden source image, which some views draw, counted as shown: moving
the source redraws where it was and is, and recoloring a traced shape
redraws only the shape.
- The renderer checks the brush library between frames only while it
keeps bounds measured with brushed strokes in 3D art.
- Tests: the sweep of 3D art's bounds counted while the art is held,
and Fit to Artwork Bounds' menu answer kept for a revision.
When an edit changes an object, the canvas draws again only the area
the object painted before and after it, measured by its cull bounds.
Type and groups with Extrude & Bevel, Inflate or Rotate were measured by
their letters or members, not by the solid the effect draws, which
reaches well past them. Making the solid shallower or turning it left
pieces of the old solid on the canvas outside that area until the view
was drawn again.
An object with a 3D effect is now measured by the effect's art, as the
renderer draws it: with its geometry effects, each object in it with
the raster effects of its own fills and strokes and the art its brushed
strokes draw, grown by the reach of the object's own raster effects.
One function measures that art for every bounds the renderer and
exports take, where three copies of it disagreed.
- The renderer measures the art it draws. What it makes to measure an
object it holds until the frame ends, with what the art read from
outside the object (fonts, symbols, color settings), and keeps it
with the art it draws if it draws the object while that is
unchanged. Art measured but not drawn (culled, off the view) isn't
kept. It holds at most as much as it keeps for the art it draws
(64 MB); past that, an object is made again to draw it. An object
whose 3D effect builds nothing (Revolve on a group, a solid too
complex) is measured as it is drawn otherwise, as without a renderer.
FrameStats::three_d_built counts the 3D art the renderer makes.
- The canvas measures what an edit changed through the renderer that
drew the frame shown (Renderer::changed). When it draws the part on
its own thread, it draws it with the art it made to measure it; when
the render worker draws the frame, or nothing in view changed, that
art is let go. Under Overprint Preview or Separations Preview, which
draw copies of the objects, the edit is measured afresh. An object
the frame doesn't draw (hidden, in a hidden group or layer, or
hidden by the view) is measured as nothing, before and after, so an
edit to it builds no solid: changed() without a renderer counts it as
nothing too, where it measured it. The canvas measures the edit
before it knows where the frame is drawn: when the worker draws it,
the solids it built to measure it are built again there.
- Fit to Artwork Bounds, the Artboards panel's check for it and
per-artboard SVG export measure every artboard through one renderer
(Renderer::art_bounds_on, Renderer::effect_bounds), which keeps each
object's bounds for the pass, a group holding 3D art or a hidden
member included, so each solid is built once: 30 extruded type
objects over 30 artboards take about 2 ms, where measuring their
letters took under 1 ms and building each solid for each artboard
would take 70 ms. Objects with brushed strokes, which culling leaves
room for and exports don't, are measured on each artboard. The
Artboard tool's canvas menu keeps whether Fit to Artwork Bounds has
art to fit for the document's revision, where it measured it on
every frame it was open.
- Other exports, Object › Rasterize and changed() without a renderer
build the art on each call, as 3D paths and groups already did.
Exports and Rasterize now take the solid of 3D type, where they
cropped it to the letters, and the art its brushed strokes draw, not
the room culling leaves for it. Rasterize on drawn 3D art measures it
once while the art is kept.
- A shadow after a 3D effect, on the object or on a fill after the
fill's own 3D effect, reaches past the solid once; it was counted
twice.
- With Crop Marks or Vector Halftone, which draw other art, the object
is measured by that art, as before.
- Culling leaves room for a 3D object's brushed strokes as for any
object's, and the renderer measures a 3D object again when the brush
library changes: a brush widened past that room would leave the
object culled.
A document's first frame builds the solid of every 3D object, those off
the view too, to know whether it reaches into the view: 200 extruded
words with 150 off the view take about 12 ms, where measuring their
letters took 6 ms.
Type whose object effects leave it as it is (Revolve builds no art from
type) is measured by its own box grown to hold its glyphs, as plain
type is; it was measured by its box alone, which needn't hold them.
A path whose live effect paints its pieces was measured with the
flattened output and the source appearance's strokes, so a piece with a
wider stroke of its own could be culled while the stroke was on screen,
and Rasterize and raster effects worked over bounds that were too small.
visual_bounds and shape_bounds now measure the art reshape returns, each
piece with its own appearance, and a raster effect on a fill or stroke
spreads that art.
A piece linked to a global swatch is drawn in the swatch's current color at its own tint, and kept art and rasters follow a color or spot edit and its Undo. A value of `paintOutput` other than true is refused by a translated error. Tests in the effects crate pass the new document argument.
A gradient placed with the Gradient tool stayed where it was when the
object's Transform or Free Distort effect moved, turned or scaled the
outline, so the shape slid across its own gradient.
The Transform effect now maps placed gradients by its own transform,
and each of its copies takes them as many times as it takes the
transform. Under Free Distort, each path's placed gradients move and
scale from the path's bounds before the effect to its bounds after it.
This change does not alter gradients fitted to the object.
The canvas, Expand Appearance and export, Pathfinder and compound
shapes, groups, a fill's or stroke's own effects, and Object › Expand
of a gradient fill apply the same rule. In a group, the own fills and
strokes of the group, of the groups inside it and of a symbol's art
follow it too, and images and symbol instances that a group's
Transform effect moves take the placed gradients of their own fills
and strokes along. A group whose path keeps its shape because the
effect would pass the geometry budget keeps its own gradients in
place.
This changes how existing documents draw: a gradient placed on a path,
or on an image's or symbol instance's own fill, inside a group with a
Transform effect now moves with it. Before, only the gradients of type
moved (#2214).
How gradients follow each effect is VectorCraft's own rule. The
Distort & Transform help page describes what the effects do to the
object:
https://helpx.adobe.com/illustrator/desktop/manage-objects/reshape-transform-objects/distort-and-transform-effects-in-illustrator.html
The reference check now applies wherever a painted effect's geometry is
used: a result whose swatch or pattern is refused keeps its input instead
of giving its geometry. Pathfinder art of type, reshaped groups, compound
shapes, image fills, the renderer's bounds and Object > Expand look the
references up in the document, and the renderer drops its kept bounds and
geometry when the names of the swatches or patterns change.
A blur or shadow over a painted piece is drawn again when a swatch or
pattern the piece names is deleted, or when the tiles of a named pattern
change. The raster's inputs now include the swatch and pattern names and
the pattern definitions for content with a plug-in effect.
Pathfinder effects, compound shapes, Expand Appearance and pattern
expansion now pass the document to the effects they evaluate, so a
painted piece that names a swatch or pattern takes part as drawn instead
of being refused. A path with a painted effect takes part in Pathfinder
and compound shapes as its pieces, each with its own paint, inside the
path's opacity and blend mode.
The renderer's kept effect art and live evaluations now count the
document's swatch and pattern names for objects with a plug-in effect,
so deleting or restoring a swatch a piece names redraws the object.
Three tests failed on a loaded machine because they asserted elapsed
time. Each now counts the work that the slow behavior it guards
against would repeat, with a counter compiled only into tests:
- The CSS cascade test counts selector tests, at most two per element
(testing every rule against every element tests N x N). It styles
5,000 elements, so the slow behavior fails on the count rather than
on the hang guard, which now waits 300 s.
- The stacked-glow test counts the silhouettes drawn, 30 for 30 glows
with and without the shadow cache.
- The Zstandard frames test counts the bytes looked at to find the
zero padding.
The hang guards for invalid dash patterns, text layout and script
checks of a pipe wait 300 s instead of 20 s.
With Real-time Drawing and Editing off, each pointer move of a drag ran one
boolean union of a group's members to draw its outline. A group of 256
overlapping ellipses took seconds per move, and at 1,024 overlapping ellipses
the union went over its budget and no outline showed.
A move or handle drag now draws the outline of each visible member of a group
or intertwine, and of each object a blend, envelope, repeat, Pathfinder effect
or object effect evaluates to, without uniting them. A gradient mesh draws its
mesh lines and a symbol instance its bounds, as their selection highlights do.
The limit of 100,000 counts outline points and evaluated objects, so a
selection past it shows its moved bounds.
A compound shape or Pathfinder effect still evaluates its boolean on each move,
and so does a clip group whose clipping path is a group.
A 3D effect on a group or layer builds a solid from every path,
compound path and type in it, all turned about one shared axis, as the
public docs describe for groups. Fixes#4506.
Inner Glow clipped to the art's outline and bled in from outside it; for a
placed image that outline is the frame, so a PNG with transparent areas
glowed along the frame's edge, over pixels that don't show. For an image the
glow is now cast by its pixels' alpha (everything around them, blurred, or
the pixels themselves with Center) and kept to where the image shows, as
much as it shows.
The renderer keeps the path of a path or compound path of 1,024 anchors
or more by object id, with the bounds of its segments and of its miter
spikes in runs of 128 segments. When anchors move and the subpaths and
anchor counts stay the same, the next frame rewrites only the path
elements of the segments that start or end at a moved anchor, and
measures again only the runs that hold them and the runs of the
segments with length before them. Other edits make the path again as
before. The pixels and the cull bounds are the same.
- StrokeLayer::bounds_on is unchanged. The miter tip of one joint
(miter_tip) and the stroke box with given tips (bounds_with_tips) are
new functions beside it, and Appearance::stroked_bounds_by takes the
box of each shaped stroke, so the cull bounds of a kept path use the
kept tips.
- geom::bez::has_length is the predicate reach.rs used for segments
that draw, made public.
Docs: docs/target-app-parity.md.